001: // $Id: Configurator.java,v 1.16 2006/01/14 14:00:42 belaban Exp $
002:
003: package org.jgroups.stack;
004:
005: import org.apache.commons.logging.Log;
006: import org.apache.commons.logging.LogFactory;
007: import org.jgroups.Event;
008: import org.jgroups.util.Util;
009:
010: import java.util.Properties;
011: import java.util.StringTokenizer;
012: import java.util.Vector;
013:
014: /**
015: * The task if this class is to setup and configure the protocol stack. A string describing
016: * the desired setup, which is both the layering and the configuration of each layer, is
017: * given to the configurator which creates and configures the protocol stack and returns
018: * a reference to the top layer (Protocol).<p>
019: * Future functionality will include the capability to dynamically modify the layering
020: * of the protocol stack and the properties of each layer.
021: * @author Bela Ban
022: */
023: public class Configurator {
024:
025: protected final Log log = LogFactory.getLog(getClass());
026:
027: /**
028: * The configuration string has a number of entries, separated by a ':' (colon).
029: * Each entry consists of the name of the protocol, followed by an optional configuration
030: * of that protocol. The configuration is enclosed in parentheses, and contains entries
031: * which are name/value pairs connected with an assignment sign (=) and separated by
032: * a semicolon.
033: * <pre>UDP(in_port=5555;out_port=4445):FRAG(frag_size=1024)</pre><p>
034: * The <em>first</em> entry defines the <em>bottommost</em> layer, the string is parsed
035: * left to right and the protocol stack constructed bottom up. Example: the string
036: * "UDP(in_port=5555):FRAG(frag_size=32000):DEBUG" results is the following stack:<pre>
037: *
038: * -----------------------
039: * | DEBUG |
040: * |-----------------------|
041: * | FRAG frag_size=32000 |
042: * |-----------------------|
043: * | UDP in_port=32000 |
044: * -----------------------
045: * </pre>
046: */
047: public Protocol setupProtocolStack(String configuration,
048: ProtocolStack st) throws Exception {
049: Protocol protocol_stack = null;
050: Vector protocol_configs;
051: Vector protocols;
052:
053: protocol_configs = parseConfigurations(configuration);
054: protocols = createProtocols(protocol_configs, st);
055: if (protocols == null)
056: return null;
057: protocol_stack = connectProtocols(protocols);
058: return protocol_stack;
059: }
060:
061: public void initProtocolStack(Protocol bottom_prot)
062: throws Exception {
063: while (bottom_prot != null) {
064: bottom_prot.init();
065: bottom_prot = bottom_prot.getUpProtocol();
066: }
067: }
068:
069: public void startProtocolStack(Protocol bottom_prot) {
070: while (bottom_prot != null) {
071: bottom_prot.startDownHandler();
072: bottom_prot.startUpHandler();
073: bottom_prot = bottom_prot.getUpProtocol();
074: }
075: }
076:
077: public void stopProtocolStack(Protocol start_prot) {
078: while (start_prot != null) {
079: start_prot.stopInternal();
080: start_prot.destroy();
081: start_prot = start_prot.getDownProtocol();
082: }
083: }
084:
085: public Protocol findProtocol(Protocol prot_stack, String name) {
086: String s;
087: Protocol curr_prot = prot_stack;
088:
089: while (true) {
090: s = curr_prot.getName();
091: if (s == null)
092: continue;
093: if (s.equals(name))
094: return curr_prot;
095: curr_prot = curr_prot.getDownProtocol();
096: if (curr_prot == null)
097: break;
098: }
099: return null;
100: }
101:
102: public Protocol getBottommostProtocol(Protocol prot_stack) {
103: Protocol tmp = null, curr_prot = prot_stack;
104:
105: while (true) {
106: if ((tmp = curr_prot.getDownProtocol()) == null)
107: break;
108: curr_prot = tmp;
109: }
110: return curr_prot;
111: }
112:
113: /**
114: * Creates a new protocol given the protocol specification. Initializes the properties and starts the
115: * up and down handler threads.
116: * @param prot_spec The specification of the protocol. Same convention as for specifying a protocol stack.
117: * An exception will be thrown if the class cannot be created. Example:
118: * <pre>"VERIFY_SUSPECT(timeout=1500)"</pre> Note that no colons (:) have to be
119: * specified
120: * @param stack The protocol stack
121: * @return Protocol The newly created protocol
122: * @exception Exception Will be thrown when the new protocol cannot be created
123: */
124: public Protocol createProtocol(String prot_spec, ProtocolStack stack)
125: throws Exception {
126: ProtocolConfiguration config;
127: Protocol prot;
128:
129: if (prot_spec == null)
130: throw new Exception(
131: "Configurator.createProtocol(): prot_spec is null");
132:
133: // parse the configuration for this protocol
134: config = new ProtocolConfiguration(prot_spec);
135:
136: // create an instance of the protocol class and configure it
137: prot = config.createLayer(stack);
138: prot.init();
139:
140: // start the handler threads (unless down_thread or up_thread are set to false)
141: prot.startDownHandler();
142: prot.startUpHandler();
143:
144: return prot;
145: }
146:
147: /**
148: * Inserts an already created (and initialized) protocol into the protocol list. Sets the links
149: * to the protocols above and below correctly and adjusts the linked list of protocols accordingly.
150: * @param prot The protocol to be inserted. Before insertion, a sanity check will ensure that none
151: * of the existing protocols have the same name as the new protocol.
152: * @param position Where to place the protocol with respect to the neighbor_prot (ABOVE, BELOW)
153: * @param neighbor_prot The name of the neighbor protocol. An exception will be thrown if this name
154: * is not found
155: * @param stack The protocol stack
156: * @exception Exception Will be thrown when the new protocol cannot be created, or inserted.
157: */
158: public void insertProtocol(Protocol prot, int position,
159: String neighbor_prot, ProtocolStack stack) throws Exception {
160: if (neighbor_prot == null)
161: throw new Exception(
162: "Configurator.insertProtocol(): neighbor_prot is null");
163: if (position != ProtocolStack.ABOVE
164: && position != ProtocolStack.BELOW)
165: throw new Exception(
166: "Configurator.insertProtocol(): position has to be ABOVE or BELOW");
167:
168: // find the neighbors below and above
169:
170: // connect to the protocol layer below and above
171:
172: }
173:
174: /**
175: * Removes a protocol from the stack. Stops the protocol and readjusts the linked lists of
176: * protocols.
177: * @param prot_name The name of the protocol. Since all protocol names in a stack have to be unique
178: * (otherwise the stack won't be created), the name refers to just 1 protocol.
179: * @exception Exception Thrown if the protocol cannot be stopped correctly.
180: */
181: public void removeProtocol(String prot_name) throws Exception {
182: }
183:
184: /* ------------------------------- Private Methods ------------------------------------- */
185:
186: /**
187: * Creates a protocol stack by iterating through the protocol list and connecting
188: * adjacent layers. The list starts with the topmost layer and has the bottommost
189: * layer at the tail. When all layers are connected the algorithms traverses the list
190: * once more to call startInternal() on each layer.
191: * @param protocol_list List of Protocol elements (from top to bottom)
192: * @return Protocol stack
193: */
194: private Protocol connectProtocols(Vector protocol_list) {
195: Protocol current_layer = null, next_layer = null;
196:
197: for (int i = 0; i < protocol_list.size(); i++) {
198: current_layer = (Protocol) protocol_list.elementAt(i);
199: if (i + 1 >= protocol_list.size())
200: break;
201: next_layer = (Protocol) protocol_list.elementAt(i + 1);
202: current_layer.setUpProtocol(next_layer);
203: next_layer.setDownProtocol(current_layer);
204: }
205: return current_layer;
206: }
207:
208: /**
209: * Get a string of the form "P1(config_str1):P2:P3(config_str3)" and return
210: * ProtocolConfigurations for it. That means, parse "P1(config_str1)", "P2" and
211: * "P3(config_str3)"
212: * @param config_str Configuration string
213: * @return Vector of ProtocolConfigurations
214: */
215: public Vector parseComponentStrings(String config_str,
216: String delimiter) {
217: Vector retval = new Vector();
218: StringTokenizer tok;
219: String token;
220:
221: /*tok=new StringTokenizer(config_str, delimiter, false);
222: while(tok.hasMoreTokens()) {
223: token=tok.nextToken();
224: retval.addElement(token);
225: }*/
226: // change suggested by gwoolsey
227: tok = new StringTokenizer(config_str, delimiter, false);
228: while (tok.hasMoreTokens()) {
229: token = tok.nextToken();
230: while (token.endsWith("\\"))
231: token = token.substring(0, token.length() - 1)
232: + delimiter + tok.nextToken();
233: retval.addElement(token);
234: }
235:
236: return retval;
237: }
238:
239: /**
240: * Return a number of ProtocolConfigurations in a vector
241: * @param configuration protocol-stack configuration string
242: * @return Vector of ProtocolConfigurations
243: */
244: public Vector parseConfigurations(String configuration)
245: throws Exception {
246: Vector retval = new Vector();
247: Vector component_strings = parseComponentStrings(configuration,
248: ":");
249: String component_string;
250: ProtocolConfiguration protocol_config;
251:
252: if (component_strings == null)
253: return null;
254: for (int i = 0; i < component_strings.size(); i++) {
255: component_string = (String) component_strings.elementAt(i);
256: protocol_config = new ProtocolConfiguration(
257: component_string);
258: retval.addElement(protocol_config);
259: }
260: return retval;
261: }
262:
263: /**
264: * Takes vector of ProtocolConfigurations, iterates through it, creates Protocol for
265: * each ProtocolConfiguration and returns all Protocols in a vector.
266: * @param protocol_configs Vector of ProtocolConfigurations
267: * @param stack The protocol stack
268: * @return Vector of Protocols
269: */
270: private Vector createProtocols(Vector protocol_configs,
271: ProtocolStack stack) throws Exception {
272: Vector retval = new Vector();
273: ProtocolConfiguration protocol_config;
274: Protocol layer;
275:
276: for (int i = 0; i < protocol_configs.size(); i++) {
277: protocol_config = (ProtocolConfiguration) protocol_configs
278: .elementAt(i);
279: layer = protocol_config.createLayer(stack);
280: if (layer == null)
281: return null;
282: retval.addElement(layer);
283: }
284: sanityCheck(retval);
285: return retval;
286: }
287:
288: /**
289: Throws an exception if sanity check fails. Possible sanity check is uniqueness of all protocol
290: names.
291: */
292: public void sanityCheck(Vector protocols) throws Exception {
293: Vector names = new Vector();
294: Protocol prot;
295: String name;
296: ProtocolReq req;
297: Vector req_list = new Vector();
298: int evt_type;
299:
300: // Checks for unique names
301: for (int i = 0; i < protocols.size(); i++) {
302: prot = (Protocol) protocols.elementAt(i);
303: name = prot.getName();
304: for (int j = 0; j < names.size(); j++) {
305: if (name.equals(names.elementAt(j))) {
306: throw new Exception(
307: "Configurator.sanityCheck(): protocol name "
308: + name
309: + " has been used more than once; protocol names have to be unique !");
310: }
311: }
312: names.addElement(name);
313: }
314:
315: // Checks whether all requirements of all layers are met
316: for (int i = 0; i < protocols.size(); i++) {
317: prot = (Protocol) protocols.elementAt(i);
318: req = new ProtocolReq(prot.getName());
319: req.up_reqs = prot.requiredUpServices();
320: req.down_reqs = prot.requiredDownServices();
321: req.up_provides = prot.providedUpServices();
322: req.down_provides = prot.providedDownServices();
323: req_list.addElement(req);
324: }
325:
326: for (int i = 0; i < req_list.size(); i++) {
327: req = (ProtocolReq) req_list.elementAt(i);
328:
329: // check whether layers above this one provide corresponding down services
330: if (req.up_reqs != null) {
331: for (int j = 0; j < req.up_reqs.size(); j++) {
332: evt_type = ((Integer) req.up_reqs.elementAt(j))
333: .intValue();
334:
335: if (!providesDownServices(i, req_list, evt_type)) {
336: throw new Exception(
337: "Configurator.sanityCheck(): event "
338: + Event.type2String(evt_type)
339: + " is required by "
340: + req.name
341: + ", but not provided by any of the layers above");
342: }
343: }
344: }
345:
346: // check whether layers below this one provide corresponding up services
347: if (req.down_reqs != null) { // check whether layers above this one provide up_reqs
348: for (int j = 0; j < req.down_reqs.size(); j++) {
349: evt_type = ((Integer) req.down_reqs.elementAt(j))
350: .intValue();
351:
352: if (!providesUpServices(i, req_list, evt_type)) {
353: throw new Exception(
354: "Configurator.sanityCheck(): event "
355: + Event.type2String(evt_type)
356: + " is required by "
357: + req.name
358: + ", but not provided by any of the layers below");
359: }
360: }
361: }
362:
363: }
364: }
365:
366: /** Check whether any of the protocols 'below' end_index provide evt_type */
367: boolean providesUpServices(int end_index, Vector req_list,
368: int evt_type) {
369: ProtocolReq req;
370:
371: for (int i = 0; i < end_index; i++) {
372: req = (ProtocolReq) req_list.elementAt(i);
373: if (req.providesUpService(evt_type))
374: return true;
375: }
376: return false;
377: }
378:
379: /** Checks whether any of the protocols 'above' start_index provide evt_type */
380: boolean providesDownServices(int start_index, Vector req_list,
381: int evt_type) {
382: ProtocolReq req;
383:
384: for (int i = start_index; i < req_list.size(); i++) {
385: req = (ProtocolReq) req_list.elementAt(i);
386: if (req.providesDownService(evt_type))
387: return true;
388: }
389: return false;
390: }
391:
392: /* --------------------------- End of Private Methods ---------------------------------- */
393:
394: private static class ProtocolReq {
395: Vector up_reqs = null;
396: Vector down_reqs = null;
397: Vector up_provides = null;
398: Vector down_provides = null;
399: String name = null;
400:
401: ProtocolReq(String name) {
402: this .name = name;
403: }
404:
405: boolean providesUpService(int evt_type) {
406: int type;
407:
408: if (up_provides != null) {
409: for (int i = 0; i < up_provides.size(); i++) {
410: type = ((Integer) up_provides.elementAt(i))
411: .intValue();
412: if (type == evt_type)
413: return true;
414: }
415: }
416: return false;
417: }
418:
419: boolean providesDownService(int evt_type) {
420: int type;
421:
422: if (down_provides != null) {
423: for (int i = 0; i < down_provides.size(); i++) {
424: type = ((Integer) down_provides.elementAt(i))
425: .intValue();
426: if (type == evt_type)
427: return true;
428: }
429: }
430: return false;
431: }
432:
433: public String toString() {
434: StringBuffer ret = new StringBuffer();
435: ret.append('\n' + name + ':');
436: if (up_reqs != null)
437: ret.append("\nRequires from above: " + printUpReqs());
438:
439: if (down_reqs != null)
440: ret.append("\nRequires from below: " + printDownReqs());
441:
442: if (up_provides != null)
443: ret.append("\nProvides to above: " + printUpProvides());
444:
445: if (down_provides != null)
446: ret.append("\nProvides to below: ").append(
447: printDownProvides());
448: return ret.toString();
449: }
450:
451: String printUpReqs() {
452: StringBuffer ret = new StringBuffer("[");
453: if (up_reqs != null) {
454: for (int i = 0; i < up_reqs.size(); i++) {
455: ret.append(Event.type2String(((Integer) up_reqs
456: .elementAt(i)).intValue()) + ' ');
457: }
458: }
459: return ret.toString() + ']';
460: }
461:
462: String printDownReqs() {
463: StringBuffer ret = new StringBuffer("[");
464: if (down_reqs != null) {
465: for (int i = 0; i < down_reqs.size(); i++) {
466: ret.append(Event.type2String(((Integer) down_reqs
467: .elementAt(i)).intValue()) + ' ');
468: }
469: }
470: return ret.toString() + ']';
471: }
472:
473: String printUpProvides() {
474: StringBuffer ret = new StringBuffer("[");
475: if (up_provides != null) {
476: for (int i = 0; i < up_provides.size(); i++) {
477: ret.append(Event.type2String(((Integer) up_provides
478: .elementAt(i)).intValue()) + ' ');
479: }
480: }
481: return ret.toString() + ']';
482: }
483:
484: String printDownProvides() {
485: StringBuffer ret = new StringBuffer("[");
486: if (down_provides != null) {
487: for (int i = 0; i < down_provides.size(); i++)
488: ret.append(Event
489: .type2String(((Integer) down_provides
490: .elementAt(i)).intValue()) + ' ');
491: }
492: return ret.toString() + ']';
493: }
494:
495: }
496:
497: /**
498: * Parses and encapsulates the specification for 1 protocol of the protocol stack, e.g.
499: * <code>UNICAST(timeout=5000)</code>
500: */
501: public class ProtocolConfiguration {
502: private String protocol_name = null;
503: private String properties_str = null;
504: private final Properties properties = new Properties();
505: private static final String protocol_prefix = "org.jgroups.protocols";
506:
507: /**
508: * Creates a new ProtocolConfiguration.
509: * @param config_str The configuration specification for the protocol, e.g.
510: * <pre>VERIFY_SUSPECT(timeout=1500)</pre>
511: */
512: public ProtocolConfiguration(String config_str)
513: throws Exception {
514: setContents(config_str);
515: }
516:
517: public String getProtocolName() {
518: return protocol_name;
519: }
520:
521: public Properties getProperties() {
522: return properties;
523: }
524:
525: void setContents(String config_str) throws Exception {
526: int index = config_str.indexOf('('); // e.g. "UDP(in_port=3333)"
527: int end_index = config_str.lastIndexOf(')');
528:
529: if (index == -1) {
530: protocol_name = config_str;
531: } else {
532: if (end_index == -1) {
533: throw new Exception(
534: "Configurator.ProtocolConfiguration.setContents(): closing ')' "
535: + "not found in " + config_str
536: + ": properties cannot be set !");
537: } else {
538: properties_str = config_str.substring(index + 1,
539: end_index);
540: protocol_name = config_str.substring(0, index);
541: }
542: }
543:
544: /* "in_port=5555;out_port=6666" */
545: if (properties_str != null) {
546: Vector components = parseComponentStrings(
547: properties_str, ";");
548: if (components.size() > 0) {
549: for (int i = 0; i < components.size(); i++) {
550: String name, value, comp = (String) components
551: .elementAt(i);
552: index = comp.indexOf('=');
553: if (index == -1) {
554: throw new Exception(
555: "Configurator.ProtocolConfiguration.setContents(): "
556: + "'=' not found in "
557: + comp);
558: }
559: name = comp.substring(0, index);
560: value = comp
561: .substring(index + 1, comp.length());
562: properties.put(name, value);
563: }
564: }
565: }
566: }
567:
568: private Protocol createLayer(ProtocolStack prot_stack)
569: throws Exception {
570: Protocol retval = null;
571: if (protocol_name == null)
572: return null;
573:
574: String defaultProtocolName = protocol_prefix + '.'
575: + protocol_name;
576: Class clazz = null;
577:
578: try {
579: clazz = Util.loadClass(defaultProtocolName, this
580: .getClass());
581: } catch (ClassNotFoundException e) {
582: }
583:
584: if (clazz == null) {
585: try {
586: clazz = Util.loadClass(protocol_name, this
587: .getClass());
588: } catch (ClassNotFoundException e) {
589: }
590: if (clazz == null) {
591: throw new Exception(
592: "unable to load class for protocol "
593: + protocol_name
594: + " (either as an absolute - "
595: + protocol_name
596: + " - or relative - "
597: + defaultProtocolName
598: + " - package name)!");
599: }
600: }
601:
602: try {
603: retval = (Protocol) clazz.newInstance();
604:
605: if (retval == null)
606: throw new Exception(
607: "creation of instance for protocol "
608: + protocol_name + "failed !");
609: retval.setProtocolStack(prot_stack);
610: if (properties != null)
611: if (!retval.setPropertiesInternal(properties))
612: return null;
613: // retval.init(); // moved to after creation of *all* protocols
614: } catch (InstantiationException inst_ex) {
615: log
616: .error("an instance of "
617: + protocol_name
618: + " could not be created. Please check that it implements"
619: + " interface Protocol and that is has a public empty constructor !");
620: throw inst_ex;
621: }
622: return retval;
623: }
624:
625: public String toString() {
626: StringBuffer retval = new StringBuffer();
627: retval.append("Protocol: ");
628: if (protocol_name == null)
629: retval.append("<unknown>");
630: else
631: retval.append(protocol_name);
632: if (properties != null)
633: retval.append("(" + properties + ')');
634: return retval.toString();
635: }
636: }
637:
638: public static void main(String args[]) {
639: if (args.length != 1) {
640: System.err.println("Configurator <string>");
641: System.exit(0);
642: }
643: String config_str = args[0];
644: Configurator conf = new Configurator();
645: Vector protocol_configs;
646: Vector protocols = null;
647: Protocol protocol_stack;
648:
649: try {
650: protocol_configs = conf.parseConfigurations(config_str);
651: protocols = conf.createProtocols(protocol_configs, null);
652: if (protocols == null)
653: return;
654: protocol_stack = conf.connectProtocols(protocols);
655: Thread.sleep(3000);
656: conf.stopProtocolStack(protocol_stack);
657: // conf.stopProtocolStackInternal(protocol_stack);
658: } catch (Exception e) {
659: System.err.println(e);
660: }
661:
662: System.err.println(protocols);
663: }
664:
665: }
|