001: package org.jgroups.conf;
002:
003: import org.w3c.dom.Element;
004: import org.apache.commons.logging.Log;
005: import org.apache.commons.logging.LogFactory;
006:
007: import org.jgroups.ChannelException;
008: import org.jgroups.JChannel;
009: import org.jgroups.util.Util;
010:
011: import java.io.*;
012:
013: import java.net.MalformedURLException;
014: import java.net.URL;
015:
016: import java.util.Properties;
017: import java.util.HashMap;
018: import java.util.Map;
019: import java.util.Iterator;
020: import java.security.AccessControlException;
021:
022: /**
023: * The ConfigurationFactory is a factory that returns a protocol stack configurator.
024: * The protocol stack configurator is an object that read a stack configuration and
025: * parses it so that the ProtocolStack can create a stack.
026: * <BR>
027: * Currently the factory returns one of the following objects:<BR>
028: * 1. XmlConfigurator - parses XML files<BR>
029: * 2. PlainConfigurator - uses the old style strings UDP:FRAG: etc etc<BR>
030: *
031: * @author Filip Hanik (<a href="mailto:filip@filip.net">filip@filip.net)
032: * @author Bela Ban
033: * @version $Id: ConfiguratorFactory.java,v 1.22 2006/10/09 13:34:00 belaban Exp $
034: */
035: public class ConfiguratorFactory {
036: public static final String JAXP_MISSING_ERROR_MSG = "JAXP Error: the required XML parsing classes are not available; "
037: + "make sure that JAXP compatible libraries are in the classpath.";
038:
039: static final String FORCE_CONFIGURATION = "force.properties";
040:
041: static final Log log = LogFactory.getLog(ConfiguratorFactory.class);
042:
043: static String propertiesOverride = null;
044:
045: // Check for the presence of the system property "force.properties", and
046: // act appropriately if it is set. We only need to do this once since the
047: // system properties are highly unlikely to change.
048: static {
049: try {
050: Properties properties = System.getProperties();
051: propertiesOverride = properties
052: .getProperty(FORCE_CONFIGURATION);
053: } catch (SecurityException e) {
054: propertiesOverride = null;
055: }
056:
057: if (propertiesOverride != null && log.isInfoEnabled()) {
058: log
059: .info("using properties override: "
060: + propertiesOverride);
061: }
062: }
063:
064: protected ConfiguratorFactory() {
065: }
066:
067: /**
068: * Returns a protocol stack configurator based on the XML configuration
069: * provided by the specified File.
070: *
071: * @param file a File with a JGroups XML configuration.
072: *
073: * @return a <code>ProtocolStackConfigurator</code> containing the stack
074: * configuration.
075: *
076: * @throws ChannelException if problems occur during the configuration of
077: * the protocol stack.
078: */
079: public static ProtocolStackConfigurator getStackConfigurator(
080: File file) throws ChannelException {
081: ProtocolStackConfigurator returnValue;
082:
083: if (propertiesOverride != null) {
084: returnValue = getStackConfigurator(propertiesOverride);
085: } else {
086: try {
087: checkJAXPAvailability();
088: InputStream input = getConfigStream(file);
089: returnValue = XmlConfigurator.getInstance(input);
090: } catch (Exception ex) {
091: throw createChannelConfigurationException(ex);
092: }
093: }
094: return returnValue;
095: }
096:
097: /**
098: * Returns a protocol stack configurator based on the XML configuration
099: * provided at the specified URL.
100: *
101: * @param url a URL pointing to a JGroups XML configuration.
102: *
103: * @return a <code>ProtocolStackConfigurator</code> containing the stack
104: * configuration.
105: *
106: * @throws ChannelException if problems occur during the configuration of
107: * the protocol stack.
108: */
109: public static ProtocolStackConfigurator getStackConfigurator(URL url)
110: throws ChannelException {
111: ProtocolStackConfigurator returnValue;
112:
113: if (propertiesOverride != null) {
114: returnValue = getStackConfigurator(propertiesOverride);
115: } else {
116: checkForNullConfiguration(url);
117: checkJAXPAvailability();
118:
119: try {
120: returnValue = XmlConfigurator.getInstance(url);
121: } catch (IOException ioe) {
122: throw createChannelConfigurationException(ioe);
123: }
124: }
125:
126: return returnValue;
127: }
128:
129: /**
130: * Returns a protocol stack configurator based on the XML configuration
131: * provided by the specified XML element.
132: *
133: * @param element a XML element containing a JGroups XML configuration.
134: *
135: * @return a <code>ProtocolStackConfigurator</code> containing the stack
136: * configuration.
137: *
138: * @throws ChannelException if problems occur during the configuration of
139: * the protocol stack.
140: */
141: public static ProtocolStackConfigurator getStackConfigurator(
142: Element element) throws ChannelException {
143: ProtocolStackConfigurator returnValue;
144:
145: if (propertiesOverride != null) {
146: returnValue = getStackConfigurator(propertiesOverride);
147: } else {
148: checkForNullConfiguration(element);
149:
150: // Since Element is a part of the JAXP specification and because an
151: // Element instance already exists, there is no need to check for
152: // JAXP availability.
153: //
154: // checkJAXPAvailability();
155:
156: try {
157: returnValue = XmlConfigurator.getInstance(element);
158: } catch (IOException ioe) {
159: throw createChannelConfigurationException(ioe);
160: }
161: }
162:
163: return returnValue;
164: }
165:
166: /**
167: * Returns a protocol stack configurator based on the provided properties
168: * string.
169: *
170: * @param properties an old style property string, a string representing a
171: * system resource containing a JGroups XML configuration,
172: * a string representing a URL pointing to a JGroups XML
173: * XML configuration, or a string representing a file name
174: * that contains a JGroups XML configuration.
175: */
176: public static ProtocolStackConfigurator getStackConfigurator(
177: String properties) throws ChannelException {
178: if (propertiesOverride != null) {
179: properties = propertiesOverride;
180: }
181:
182: // added by bela: for null String props we use the default properties
183: if (properties == null)
184: properties = JChannel.DEFAULT_PROTOCOL_STACK;
185:
186: checkForNullConfiguration(properties);
187:
188: ProtocolStackConfigurator returnValue;
189:
190: // Attempt to treat the properties string as a pointer to an XML
191: // configuration.
192: XmlConfigurator configurator = null;
193:
194: try {
195: configurator = getXmlConfigurator(properties);
196: } catch (IOException ioe) {
197: throw createChannelConfigurationException(ioe);
198: }
199:
200: // Did the properties string point to a JGroups XML configuration?
201: if (configurator != null) {
202: returnValue = configurator;
203: } else {
204: // Attempt to process the properties string as the old style
205: // property string.
206: returnValue = new PlainConfigurator(properties);
207: }
208:
209: return returnValue;
210: }
211:
212: /**
213: * Returns a protocol stack configurator based on the properties passed in.<BR>
214: * If the properties parameter is a plain string UDP:FRAG:MERGE:GMS etc, a PlainConfigurator is returned.<BR>
215: * If the properties parameter is a string that represents a url for example http://www.filip.net/test.xml
216: * or the parameter is a java.net.URL object, an XmlConfigurator is returned<BR>
217: *
218: * @param properties old style property string, url string, or java.net.URL object
219: * @return a ProtocolStackConfigurator containing the stack configuration
220: * @throws IOException if it fails to parse the XML content
221: * @throws IOException if the URL is invalid or a the content can not be reached
222: * @deprecated Used by the JChannel(Object) constructor which has been deprecated.
223: */
224: public static ProtocolStackConfigurator getStackConfigurator(
225: Object properties) throws IOException {
226: InputStream input = null;
227:
228: if (propertiesOverride != null) {
229: properties = propertiesOverride;
230: }
231:
232: // added by bela: for null String props we use the default properties
233: if (properties == null)
234: properties = JChannel.DEFAULT_PROTOCOL_STACK;
235:
236: if (properties instanceof URL) {
237: try {
238: input = ((URL) properties).openStream();
239: } catch (Throwable t) {
240: }
241: }
242:
243: // if it is a string, then it could be a plain string or a url
244: if (input == null && properties instanceof String) {
245: try {
246: input = new URL((String) properties).openStream();
247: } catch (Exception ignore) {
248: // if we get here this means we don't have a URL
249: }
250:
251: // another try - maybe it is a resource, e.g. udp.xml
252: if (input == null && ((String) properties).endsWith("xml")) {
253: try {
254: input = Util.getResourceAsStream(
255: (String) properties,
256: ConfiguratorFactory.class);
257: } catch (Throwable ignore) {
258: }
259: }
260:
261: // try a regular file name
262: //
263: // This code was moved from the parent block (below) because of the
264: // possibility of causing a ClassCastException.
265:
266: if (input == null) {
267: try {
268: input = new FileInputStream((String) properties);
269: } catch (Throwable t) {
270: }
271: }
272: }
273:
274: // try a regular file
275: if (input == null && properties instanceof File) {
276: try {
277: input = new FileInputStream((File) properties);
278: } catch (Throwable t) {
279: }
280: }
281:
282: if (input != null) {
283: return XmlConfigurator.getInstance(input);
284: }
285:
286: if (properties instanceof Element) {
287: return XmlConfigurator.getInstance((Element) properties);
288: }
289:
290: return new PlainConfigurator((String) properties);
291: }
292:
293: public static InputStream getConfigStream(File file)
294: throws Exception {
295: if (propertiesOverride != null)
296: return getConfigStream(propertiesOverride);
297:
298: checkForNullConfiguration(file);
299:
300: try {
301: return new FileInputStream(file);
302: } catch (IOException ioe) {
303: throw createChannelConfigurationException(ioe);
304: }
305: }
306:
307: public static InputStream getConfigStream(URL url) throws Exception {
308: if (propertiesOverride != null)
309: return getConfigStream(propertiesOverride);
310: try {
311: checkJAXPAvailability();
312: return url.openStream();
313: } catch (Exception ex) {
314: throw createChannelConfigurationException(ex);
315: }
316: }
317:
318: /**
319: * Returns a JGroups XML configuration InputStream based on the provided
320: * properties string.
321: *
322: * @param properties a string representing a system resource containing a
323: * JGroups XML configuration, a string representing a URL
324: * pointing to a JGroups ML configuration, or a string
325: * representing a file name that contains a JGroups XML
326: * configuration.
327: *
328: * @throws IOException if the provided properties string appears to be a
329: * valid URL but is unreachable.
330: */
331: public static InputStream getConfigStream(String properties)
332: throws IOException {
333: InputStream configStream = null;
334: if (propertiesOverride != null)
335: return getConfigStream(propertiesOverride);
336:
337: // Check to see if the properties string is the name of a file.
338: try {
339: configStream = new FileInputStream(properties);
340: } catch (FileNotFoundException fnfe) {
341: // the properties string is likely not a file
342: } catch (AccessControlException access_ex) {
343: // fixes http://jira.jboss.com/jira/browse/JGRP-94
344: }
345:
346: // Check to see if the properties string is a URL.
347: if (configStream == null) {
348: try {
349: configStream = new URL(properties).openStream();
350: } catch (MalformedURLException mre) {
351: // the properties string is not a URL
352: }
353: }
354: // Commented so the caller is notified of this condition, but left in
355: // the code for documentation purposes.
356: //
357: // catch (IOException ioe) {
358: // the specified URL string was not reachable
359: // }
360:
361: // Check to see if the properties string is the name of a resource,
362: // e.g. udp.xml.
363: if (configStream == null && properties.endsWith("xml")) {
364: configStream = Util.getResourceAsStream(properties,
365: ConfiguratorFactory.class);
366: }
367: return configStream;
368: }
369:
370: public static InputStream getConfigStream(Object properties)
371: throws IOException {
372: InputStream input = null;
373: if (propertiesOverride != null)
374: return getConfigStream(propertiesOverride);
375:
376: // added by bela: for null String props we use the default properties
377: if (properties == null)
378: properties = JChannel.DEFAULT_PROTOCOL_STACK;
379:
380: if (properties instanceof URL) {
381: try {
382: input = ((URL) properties).openStream();
383: } catch (Throwable t) {
384: }
385: }
386:
387: // if it is a string, then it could be a plain string or a url
388: if (input == null && properties instanceof String) {
389: input = getConfigStream((String) properties);
390: }
391:
392: // try a regular file
393: if (input == null && properties instanceof File) {
394: try {
395: input = new FileInputStream((File) properties);
396: } catch (Throwable t) {
397: }
398: }
399:
400: if (input != null)
401: return input;
402:
403: if (properties instanceof Element) {
404: return getConfigStream((Element) properties);
405: }
406:
407: return new ByteArrayInputStream(((String) properties)
408: .getBytes());
409: }
410:
411: /**
412: * Returns an XmlConfigurator based on the provided properties string (if
413: * possible).
414: *
415: * @param properties a string representing a system resource containing a
416: * JGroups XML configuration, a string representing a URL
417: * pointing to a JGroups ML configuration, or a string
418: * representing a file name that contains a JGroups XML
419: * configuration.
420: *
421: * @return an XmlConfigurator instance based on the provided properties
422: * string; <code>null</code> if the provided properties string does
423: * not point to an XML configuration.
424: *
425: * @throws IOException if the provided properties string appears to be a
426: * valid URL but is unreachable, or if the JGroups XML
427: * configuration pointed to by the URL can not be
428: * parsed.
429: */
430: static XmlConfigurator getXmlConfigurator(String properties)
431: throws IOException {
432: XmlConfigurator returnValue = null;
433: InputStream configStream = getConfigStream(properties);
434:
435: if (configStream != null) {
436: checkJAXPAvailability();
437: returnValue = XmlConfigurator.getInstance(configStream);
438: }
439:
440: return returnValue;
441: }
442:
443: /**
444: * Creates a <code>ChannelException</code> instance based upon a
445: * configuration problem.
446: *
447: * @param cause the exceptional configuration condition to be used as the
448: * created <code>ChannelException</code>'s cause.
449: */
450: static ChannelException createChannelConfigurationException(
451: Throwable cause) {
452: return new ChannelException(
453: "unable to load the protocol stack", cause);
454: }
455:
456: /**
457: * Check to see if the specified configuration properties are
458: * <code>null</null> which is not allowed.
459: *
460: * @param properties the specified protocol stack configuration.
461: *
462: * @throws NullPointerException if the specified configuration properties
463: * are <code>null</code>.
464: */
465: static void checkForNullConfiguration(Object properties) {
466: if (properties == null)
467: throw new NullPointerException(
468: "the specifed protocol stack configuration was null");
469: }
470:
471: /**
472: * Checks the availability of the JAXP classes on the classpath.
473: *
474: * @throws NoClassDefFoundError if the required JAXP classes are not
475: * availabile on the classpath.
476: */
477: static void checkJAXPAvailability() {
478: try {
479: // TODO: Do some real class checking here instead of forcing the
480: // load of a JGroups class that happens (by default) to do it
481: // for us.
482: XmlConfigurator.class.getName();
483: } catch (NoClassDefFoundError error) {
484: Error tmp = new NoClassDefFoundError(JAXP_MISSING_ERROR_MSG);
485: tmp.initCause(error);
486: throw tmp;
487: }
488: }
489:
490: /** Replace variables of the form ${var:default} with the getProperty(var, default)
491: * @param configurator
492: */
493: public static void substituteVariables(
494: ProtocolStackConfigurator configurator) {
495: ProtocolData[] protocols;
496:
497: try {
498: protocols = configurator.getProtocolStack();
499: } catch (Exception e) {
500: protocols = null;
501: }
502:
503: if (protocols == null)
504: return;
505: for (int i = 0; i < protocols.length; i++) {
506: ProtocolData protocol = protocols[i];
507: if (protocol != null) {
508: HashMap parms = protocol.getParameters();
509: Map.Entry entry;
510: ProtocolParameter parm;
511: for (Iterator it = parms.entrySet().iterator(); it
512: .hasNext();) {
513: entry = (Map.Entry) it.next();
514: parm = (ProtocolParameter) entry.getValue();
515: String val = parm.getValue();
516: String replacement = Util.substituteVariable(val);
517: if (!replacement.equals(val)) {
518: parm.setValue(replacement);
519: }
520: }
521: }
522: }
523:
524: }
525: }
|