PageRenderTime 211ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 1ms

/projects/jgroups-2.10.0/src/org/jgroups/stack/Configurator.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 1160 lines | 807 code | 171 blank | 182 comment | 255 complexity | 237e84d147fa8917e752aff8af99e715 MD5 | raw file
  1. package org.jgroups.stack;
  2. import org.jgroups.Event;
  3. import org.jgroups.Global;
  4. import org.jgroups.annotations.DeprecatedProperty;
  5. import org.jgroups.annotations.Property;
  6. import org.jgroups.conf.PropertyHelper;
  7. import org.jgroups.logging.Log;
  8. import org.jgroups.logging.LogFactory;
  9. import org.jgroups.protocols.TP;
  10. import org.jgroups.stack.ProtocolStack.ProtocolStackFactory;
  11. import org.jgroups.util.StackType;
  12. import org.jgroups.util.Tuple;
  13. import org.jgroups.util.Util;
  14. import java.io.IOException;
  15. import java.io.PushbackReader;
  16. import java.io.Reader;
  17. import java.io.StringReader;
  18. import java.lang.reflect.*;
  19. import java.net.Inet4Address;
  20. import java.net.Inet6Address;
  21. import java.net.InetAddress;
  22. import java.net.InetSocketAddress;
  23. import java.util.*;
  24. import java.util.concurrent.ConcurrentMap;
  25. /**
  26. * The task if this class is to setup and configure the protocol stack. A string describing
  27. * the desired setup, which is both the layering and the configuration of each layer, is
  28. * given to the configurator which creates and configures the protocol stack and returns
  29. * a reference to the top layer (Protocol).<p>
  30. * Future functionality will include the capability to dynamically modify the layering
  31. * of the protocol stack and the properties of each layer.
  32. * @author Bela Ban
  33. * @author Richard Achmatowicz
  34. * @version $Id: Configurator.java,v 1.82 2010/05/10 11:23:05 belaban Exp $
  35. */
  36. public class Configurator implements ProtocolStackFactory {
  37. protected static final Log log=LogFactory.getLog(Configurator.class);
  38. private final ProtocolStack stack;
  39. public Configurator() {
  40. stack = null;
  41. }
  42. public Configurator(ProtocolStack protocolStack) {
  43. stack=protocolStack;
  44. }
  45. public Protocol setupProtocolStack() throws Exception{
  46. return setupProtocolStack(stack.getSetupString(), stack);
  47. }
  48. public Protocol setupProtocolStack(ProtocolStack copySource)throws Exception{
  49. Vector<Protocol> protocols=copySource.copyProtocols(stack);
  50. Collections.reverse(protocols);
  51. return connectProtocols(protocols);
  52. }
  53. /**
  54. * The configuration string has a number of entries, separated by a ':' (colon).
  55. * Each entry consists of the name of the protocol, followed by an optional configuration
  56. * of that protocol. The configuration is enclosed in parentheses, and contains entries
  57. * which are name/value pairs connected with an assignment sign (=) and separated by
  58. * a semicolon.
  59. * <pre>UDP(in_port=5555;out_port=4445):FRAG(frag_size=1024)</pre><p>
  60. * The <em>first</em> entry defines the <em>bottommost</em> layer, the string is parsed
  61. * left to right and the protocol stack constructed bottom up. Example: the string
  62. * "UDP(in_port=5555):FRAG(frag_size=32000):DEBUG" results is the following stack:<pre>
  63. *
  64. * -----------------------
  65. * | DEBUG |
  66. * |-----------------------|
  67. * | FRAG frag_size=32000 |
  68. * |-----------------------|
  69. * | UDP in_port=32000 |
  70. * -----------------------
  71. * </pre>
  72. */
  73. private static Protocol setupProtocolStack(String configuration, ProtocolStack st) throws Exception {
  74. Vector<ProtocolConfiguration> protocol_configs=parseConfigurations(configuration);
  75. Vector<Protocol> protocols=createProtocols(protocol_configs, st);
  76. if(protocols == null)
  77. return null;
  78. // basic protocol sanity check
  79. sanityCheck(protocols);
  80. // check InetAddress related features of stack
  81. Map<String, Map<String,InetAddressInfo>> inetAddressMap = createInetAddressMap(protocol_configs, protocols) ;
  82. Collection<InetAddress> addrs=getAddresses(inetAddressMap);
  83. StackType ip_version=Util.getIpStackType(); // 0 = n/a, 4 = IPv4, 6 = IPv6
  84. if(!addrs.isEmpty()) {
  85. // check that all user-supplied InetAddresses have a consistent version:
  86. // 1. If an addr is IPv6 and we have an IPv4 stack --> FAIL
  87. // 2. If an address is an IPv4 class D (multicast) address and the stack is IPv6: FAIL
  88. // Else pass
  89. for(InetAddress addr: addrs) {
  90. if(addr instanceof Inet6Address && ip_version == StackType.IPv4)
  91. throw new IllegalArgumentException("found IPv6 address " + addr + " in an IPv4 stack");
  92. if(addr instanceof Inet4Address && addr.isMulticastAddress() && ip_version == StackType.IPv6)
  93. throw new Exception("found IPv4 multicast address " + addr + " in an IPv6 stack");
  94. }
  95. }
  96. // process default values
  97. setDefaultValues(protocol_configs, protocols, ip_version) ;
  98. return connectProtocols(protocols);
  99. }
  100. /**
  101. * Creates a new protocol given the protocol specification. Initializes the properties and starts the
  102. * up and down handler threads.
  103. * @param prot_spec The specification of the protocol. Same convention as for specifying a protocol stack.
  104. * An exception will be thrown if the class cannot be created. Example:
  105. * <pre>"VERIFY_SUSPECT(timeout=1500)"</pre> Note that no colons (:) have to be
  106. * specified
  107. * @param stack The protocol stack
  108. * @return Protocol The newly created protocol
  109. * @exception Exception Will be thrown when the new protocol cannot be created
  110. */
  111. public static Protocol createProtocol(String prot_spec, ProtocolStack stack) throws Exception {
  112. ProtocolConfiguration config;
  113. Protocol prot;
  114. if(prot_spec == null) throw new Exception("Configurator.createProtocol(): prot_spec is null");
  115. // parse the configuration for this protocol
  116. config=new ProtocolConfiguration(prot_spec);
  117. // create an instance of the protocol class and configure it
  118. prot=config.createLayer(stack);
  119. prot.init();
  120. return prot;
  121. }
  122. /* ------------------------------- Private Methods ------------------------------------- */
  123. /**
  124. * Creates a protocol stack by iterating through the protocol list and connecting
  125. * adjacent layers. The list starts with the topmost layer and has the bottommost
  126. * layer at the tail.
  127. * @param protocol_list List of Protocol elements (from top to bottom)
  128. * @return Protocol stack
  129. */
  130. private static Protocol connectProtocols(Vector<Protocol> protocol_list) {
  131. Protocol current_layer=null, next_layer=null;
  132. for(int i=0; i < protocol_list.size(); i++) {
  133. current_layer=protocol_list.elementAt(i);
  134. if(i + 1 >= protocol_list.size())
  135. break;
  136. next_layer=protocol_list.elementAt(i + 1);
  137. next_layer.setDownProtocol(current_layer);
  138. current_layer.setUpProtocol(next_layer);
  139. if(current_layer instanceof TP) {
  140. TP transport = (TP)current_layer;
  141. if(transport.isSingleton()) {
  142. ConcurrentMap<String, Protocol> up_prots=transport.getUpProtocols();
  143. String key;
  144. synchronized(up_prots) {
  145. while(true) {
  146. key=Global.DUMMY + System.currentTimeMillis();
  147. if(up_prots.containsKey(key))
  148. continue;
  149. up_prots.put(key, next_layer);
  150. break;
  151. }
  152. }
  153. current_layer.setUpProtocol(null);
  154. }
  155. }
  156. }
  157. return current_layer;
  158. }
  159. /**
  160. * Get a string of the form "P1(config_str1):P2:P3(config_str3)" and return
  161. * ProtocolConfigurations for it. That means, parse "P1(config_str1)", "P2" and
  162. * "P3(config_str3)"
  163. * @param config_str Configuration string
  164. * @return Vector of strings
  165. */
  166. private static Vector<String> parseProtocols(String config_str) throws IOException {
  167. Vector<String> retval=new Vector<String>();
  168. PushbackReader reader=new PushbackReader(new StringReader(config_str));
  169. int ch;
  170. StringBuilder sb;
  171. boolean running=true;
  172. while(running) {
  173. String protocol_name=readWord(reader);
  174. sb=new StringBuilder();
  175. sb.append(protocol_name);
  176. ch=read(reader);
  177. if(ch == -1) {
  178. retval.add(sb.toString());
  179. break;
  180. }
  181. if(ch == ':') { // no attrs defined
  182. retval.add(sb.toString());
  183. continue;
  184. }
  185. if(ch == '(') { // more attrs defined
  186. reader.unread(ch);
  187. String attrs=readUntil(reader, ')');
  188. sb.append(attrs);
  189. retval.add(sb.toString());
  190. }
  191. else {
  192. retval.add(sb.toString());
  193. }
  194. while(true) {
  195. ch=read(reader);
  196. if(ch == ':') {
  197. break;
  198. }
  199. if(ch == -1) {
  200. running=false;
  201. break;
  202. }
  203. }
  204. }
  205. reader.close();
  206. return retval;
  207. }
  208. private static int read(Reader reader) throws IOException {
  209. int ch=-1;
  210. while((ch=reader.read()) != -1) {
  211. if(!Character.isWhitespace(ch))
  212. return ch;
  213. }
  214. return ch;
  215. }
  216. /**
  217. * Return a number of ProtocolConfigurations in a vector
  218. * @param configuration protocol-stack configuration string
  219. * @return Vector of ProtocolConfigurations
  220. */
  221. public static Vector<ProtocolConfiguration> parseConfigurations(String configuration) throws Exception {
  222. Vector<ProtocolConfiguration> retval=new Vector<ProtocolConfiguration>();
  223. Vector<String> protocol_string=parseProtocols(configuration);
  224. if(protocol_string == null)
  225. return null;
  226. for(String component_string:protocol_string) {
  227. retval.addElement(new ProtocolConfiguration(component_string));
  228. }
  229. return retval;
  230. }
  231. public static String printConfigurations(Collection<ProtocolConfiguration> configs) {
  232. StringBuilder sb=new StringBuilder();
  233. boolean first=true;
  234. for(ProtocolConfiguration config: configs) {
  235. if(first)
  236. first=false;
  237. else
  238. sb.append(":");
  239. sb.append(config.getProtocolName());
  240. if(!config.getProperties().isEmpty()) {
  241. sb.append('(').append(config.propertiesToString()).append(')');
  242. }
  243. }
  244. return sb.toString();
  245. }
  246. private static String readUntil(Reader reader, char c) throws IOException {
  247. StringBuilder sb=new StringBuilder();
  248. int ch;
  249. while((ch=read(reader)) != -1) {
  250. sb.append((char)ch);
  251. if(ch == c)
  252. break;
  253. }
  254. return sb.toString();
  255. }
  256. private static String readWord(PushbackReader reader) throws IOException {
  257. StringBuilder sb=new StringBuilder();
  258. int ch;
  259. while((ch=read(reader)) != -1) {
  260. if(Character.isLetterOrDigit(ch) || ch == '_' || ch == '.' || ch == '$') {
  261. sb.append((char)ch);
  262. }
  263. else {
  264. reader.unread(ch);
  265. break;
  266. }
  267. }
  268. return sb.toString();
  269. }
  270. /**
  271. * Takes vector of ProtocolConfigurations, iterates through it, creates Protocol for
  272. * each ProtocolConfiguration and returns all Protocols in a vector.
  273. * @param protocol_configs Vector of ProtocolConfigurations
  274. * @param stack The protocol stack
  275. * @return Vector of Protocols
  276. */
  277. private static Vector<Protocol> createProtocols(Vector<ProtocolConfiguration> protocol_configs, final ProtocolStack stack) throws Exception {
  278. Vector<Protocol> retval=new Vector<Protocol>();
  279. ProtocolConfiguration protocol_config;
  280. Protocol layer;
  281. String singleton_name;
  282. for(int i=0; i < protocol_configs.size(); i++) {
  283. protocol_config=protocol_configs.elementAt(i);
  284. singleton_name=protocol_config.getProperties().get(Global.SINGLETON_NAME);
  285. if(singleton_name != null && singleton_name.trim().length() > 0) {
  286. Map<String,Tuple<TP, ProtocolStack.RefCounter>> singleton_transports=ProtocolStack.getSingletonTransports();
  287. synchronized(singleton_transports) {
  288. if(i > 0) { // crude way to check whether protocol is a transport
  289. throw new IllegalArgumentException("Property 'singleton_name' can only be used in a transport" +
  290. " protocol (was used in " + protocol_config.getProtocolName() + ")");
  291. }
  292. Tuple<TP, ProtocolStack.RefCounter> val=singleton_transports.get(singleton_name);
  293. layer=val != null? val.getVal1() : null;
  294. if(layer != null) {
  295. retval.add(layer);
  296. }
  297. else {
  298. layer=protocol_config.createLayer(stack);
  299. if(layer == null)
  300. return null;
  301. singleton_transports.put(singleton_name, new Tuple<TP, ProtocolStack.RefCounter>((TP)layer,new ProtocolStack.RefCounter((short)0,(short)0)));
  302. retval.addElement(layer);
  303. }
  304. }
  305. continue;
  306. }
  307. layer=protocol_config.createLayer(stack);
  308. if(layer == null)
  309. return null;
  310. retval.addElement(layer);
  311. }
  312. return retval;
  313. }
  314. /**
  315. Throws an exception if sanity check fails. Possible sanity check is uniqueness of all protocol names
  316. */
  317. public static void sanityCheck(Vector<Protocol> protocols) throws Exception {
  318. Vector<String> names=new Vector<String>();
  319. Protocol prot;
  320. String name;
  321. Vector<ProtocolReq> req_list=new Vector<ProtocolReq>();
  322. // Checks for unique names
  323. for(int i=0; i < protocols.size(); i++) {
  324. prot=protocols.elementAt(i);
  325. name=prot.getName();
  326. for(int j=0; j < names.size(); j++) {
  327. if(name.equals(names.elementAt(j))) {
  328. throw new Exception("Configurator.sanityCheck(): protocol name " + name +
  329. " has been used more than once; protocol names have to be unique !");
  330. }
  331. }
  332. names.addElement(name);
  333. }
  334. // check for unique IDs
  335. Set<Short> ids=new HashSet<Short>();
  336. for(Protocol protocol: protocols) {
  337. short id=protocol.getId();
  338. if(id > 0 && ids.add(id) == false)
  339. throw new Exception("Protocol ID " + id + " (name=" + protocol.getName() +
  340. ") is duplicate; protocol IDs have to be unique");
  341. }
  342. // Checks whether all requirements of all layers are met
  343. for(Protocol p:protocols){
  344. req_list.add(new ProtocolReq(p));
  345. }
  346. for(ProtocolReq pr:req_list){
  347. for(Integer evt_type:pr.up_reqs) {
  348. if(!providesDownServices(req_list, evt_type)) {
  349. throw new Exception("Configurator.sanityCheck(): event " +
  350. Event.type2String(evt_type) + " is required by " +
  351. pr.name + ", but not provided by any of the layers above");
  352. }
  353. }
  354. for(Integer evt_type:pr.down_reqs) {
  355. if(!providesUpServices(req_list, evt_type)) {
  356. throw new Exception("Configurator.sanityCheck(): event " +
  357. Event.type2String(evt_type) + " is required by " +
  358. pr.name + ", but not provided by any of the layers above");
  359. }
  360. }
  361. }
  362. }
  363. /**
  364. * Returns all inet addresses found
  365. */
  366. public static Collection<InetAddress> getAddresses(Map<String, Map<String, InetAddressInfo>> inetAddressMap) throws Exception {
  367. Set<InetAddress> addrs=new HashSet<InetAddress>();
  368. for(Map.Entry<String, Map<String, InetAddressInfo>> inetAddressMapEntry : inetAddressMap.entrySet()) {
  369. Map<String, InetAddressInfo> protocolInetAddressMap=inetAddressMapEntry.getValue();
  370. for(Map.Entry<String, InetAddressInfo> protocolInetAddressMapEntry : protocolInetAddressMap.entrySet()) {
  371. InetAddressInfo inetAddressInfo=protocolInetAddressMapEntry.getValue();
  372. // add InetAddressInfo to sets based on IP version
  373. List<InetAddress> addresses=inetAddressInfo.getInetAddresses();
  374. for(InetAddress address : addresses) {
  375. if(address == null)
  376. throw new RuntimeException("This address should not be null! - something is wrong");
  377. addrs.add(address);
  378. }
  379. }
  380. }
  381. return addrs;
  382. }
  383. /**
  384. * This method takes a set of InetAddresses, represented by an inetAddressmap, and:
  385. * - if the resulting set is non-empty, goes through to see if all InetAddress-related
  386. * user settings have a consistent IP version: v4 or v6, and throws an exception if not
  387. * - if the resulting set is empty, sets the default IP version based on available stacks
  388. * and if a dual stack, stack preferences
  389. * - sets the IP version to be used in the JGroups session
  390. * @return StackType.IPv4 for IPv4, StackType.IPv6 for IPv6, StackType.Unknown if the version cannot be determined
  391. */
  392. public static StackType determineIpVersionFromAddresses(Collection<InetAddress> addrs) throws Exception {
  393. Set<InetAddress> ipv4_addrs= new HashSet<InetAddress>() ;
  394. Set<InetAddress> ipv6_addrs= new HashSet<InetAddress>() ;
  395. for(InetAddress address: addrs) {
  396. if (address instanceof Inet4Address)
  397. ipv4_addrs.add(address) ;
  398. else
  399. ipv6_addrs.add(address) ;
  400. }
  401. if(log.isTraceEnabled())
  402. log.trace("all addrs=" + addrs + ", IPv4 addrs=" + ipv4_addrs + ", IPv6 addrs=" + ipv6_addrs);
  403. // the user supplied 1 or more IP address inputs. Check if we have a consistent set
  404. if (!addrs.isEmpty()) {
  405. if (!ipv4_addrs.isEmpty() && !ipv6_addrs.isEmpty()) {
  406. throw new RuntimeException("all addresses have to be either IPv4 or IPv6: IPv4 addresses=" +
  407. ipv4_addrs + ", IPv6 addresses=" + ipv6_addrs);
  408. }
  409. return !ipv6_addrs.isEmpty()? StackType.IPv6 : StackType.IPv4;
  410. }
  411. return StackType.Unknown;
  412. }
  413. /*
  414. * A method which does the following:
  415. * - discovers all Fields or Methods within the protocol stack which set
  416. * InetAddress, IpAddress, InetSocketAddress (and Lists of such) for which the user *has*
  417. * specified a default value.
  418. * - stores the resulting set of Fields and Methods in a map of the form:
  419. * Protocol -> Property -> InetAddressInfo
  420. * where InetAddressInfo instances encapsulate the InetAddress related information
  421. * of the Fields and Methods.
  422. */
  423. public static Map<String, Map<String,InetAddressInfo>> createInetAddressMap(Vector<ProtocolConfiguration> protocol_configs,
  424. Vector<Protocol> protocols) throws Exception {
  425. // Map protocol -> Map<String, InetAddressInfo>, where the latter is protocol specific
  426. Map<String, Map<String,InetAddressInfo>> inetAddressMap = new HashMap<String, Map<String, InetAddressInfo>>() ;
  427. // collect InetAddressInfo
  428. for (int i = 0; i < protocol_configs.size(); i++) {
  429. ProtocolConfiguration protocol_config = protocol_configs.get(i) ;
  430. Protocol protocol = protocols.get(i) ;
  431. String protocolName = protocol.getName();
  432. // regenerate the Properties which were destroyed during basic property processing
  433. Map<String,String> properties = protocol_config.getOriginalProperties();
  434. // check which InetAddress-related properties are ***non-null ***, and
  435. // create an InetAddressInfo structure for them
  436. // Method[] methods=protocol.getClass().getMethods();
  437. Method[] methods=Util.getAllDeclaredMethodsWithAnnotations(protocol.getClass(), Property.class);
  438. for(int j = 0; j < methods.length; j++) {
  439. if (methods[j].isAnnotationPresent(Property.class) && isSetPropertyMethod(methods[j])) {
  440. String propertyName = PropertyHelper.getPropertyName(methods[j]) ;
  441. String propertyValue = properties.get(propertyName);
  442. // if there is a systemProperty attribute defined in the annotation, set the property value from the system property
  443. String tmp=grabSystemProp(methods[j].getAnnotation(Property.class));
  444. if(tmp != null)
  445. propertyValue=tmp;
  446. if (propertyValue != null && InetAddressInfo.isInetAddressRelated(methods[j])) {
  447. Object converted = null ;
  448. try {
  449. converted=PropertyHelper.getConvertedValue(protocol, methods[j], properties, propertyValue, false);
  450. }
  451. catch(Exception e) {
  452. throw new Exception("String value could not be converted for method " + propertyName + " in "
  453. + protocolName + " with default value " + propertyValue + ".Exception is " +e, e);
  454. }
  455. InetAddressInfo inetinfo = new InetAddressInfo(protocol, methods[j], properties, propertyValue, converted) ;
  456. Map<String, InetAddressInfo> protocolInetAddressMap=inetAddressMap.get(protocolName);
  457. if(protocolInetAddressMap == null) {
  458. protocolInetAddressMap = new HashMap<String,InetAddressInfo>() ;
  459. inetAddressMap.put(protocolName, protocolInetAddressMap) ;
  460. }
  461. protocolInetAddressMap.put(propertyName, inetinfo) ;
  462. }
  463. }
  464. }
  465. //traverse class hierarchy and find all annotated fields and add them to the list if annotated
  466. for(Class<?> clazz=protocol.getClass(); clazz != null; clazz=clazz.getSuperclass()) {
  467. Field[] fields=clazz.getDeclaredFields();
  468. for(int j = 0; j < fields.length; j++ ) {
  469. if (fields[j].isAnnotationPresent(Property.class)) {
  470. String propertyName = PropertyHelper.getPropertyName(fields[j], properties) ;
  471. String propertyValue = properties.get(propertyName) ;
  472. // if there is a systemProperty attribute defined in the annotation, set the property value from the system property
  473. String tmp=grabSystemProp(fields[j].getAnnotation(Property.class));
  474. if(tmp != null)
  475. propertyValue=tmp;
  476. if ((propertyValue != null || !PropertyHelper.usesDefaultConverter(fields[j]))
  477. && InetAddressInfo.isInetAddressRelated(protocol, fields[j])) {
  478. Object converted = null ;
  479. try {
  480. converted=PropertyHelper.getConvertedValue(protocol, fields[j], properties, propertyValue, false);
  481. }
  482. catch(Exception e) {
  483. throw new Exception("String value could not be converted for method " + propertyName + " in "
  484. + protocolName + " with default value " + propertyValue + ".Exception is " +e, e);
  485. }
  486. InetAddressInfo inetinfo = new InetAddressInfo(protocol, fields[j], properties, propertyValue, converted) ;
  487. Map<String, InetAddressInfo> protocolInetAddressMap=inetAddressMap.get(protocolName);
  488. if(protocolInetAddressMap == null) {
  489. protocolInetAddressMap = new HashMap<String,InetAddressInfo>() ;
  490. inetAddressMap.put(protocolName, protocolInetAddressMap) ;
  491. }
  492. protocolInetAddressMap.put(propertyName, inetinfo) ;
  493. }// recompute
  494. }
  495. }
  496. }
  497. }
  498. return inetAddressMap ;
  499. }
  500. /*
  501. * Method which processes @Property.default() values, associated with the annotation
  502. * using the defaultValue= attribute. This method does the following:
  503. * - locate all properties which have no user value assigned
  504. * - if the defaultValue attribute is not "", generate a value for the field using the
  505. * property converter for that property and assign it to the field
  506. */
  507. public static void setDefaultValues(Vector<ProtocolConfiguration> protocol_configs, Vector<Protocol> protocols,
  508. StackType ip_version) throws Exception {
  509. InetAddress default_ip_address=Util.getNonLoopbackAddress();
  510. if(default_ip_address == null) {
  511. log.warn("unable to find an address other than loopback for IP version " + ip_version);
  512. default_ip_address=Util.getLocalhost(ip_version);
  513. }
  514. for(int i=0; i < protocol_configs.size(); i++) {
  515. ProtocolConfiguration protocol_config=protocol_configs.get(i);
  516. Protocol protocol=protocols.get(i);
  517. String protocolName=protocol.getName();
  518. // regenerate the Properties which were destroyed during basic property processing
  519. Map<String,String> properties=protocol_config.getOriginalProperties();
  520. Method[] methods=Util.getAllDeclaredMethodsWithAnnotations(protocol.getClass(), Property.class);
  521. for(int j=0; j < methods.length; j++) {
  522. if(isSetPropertyMethod(methods[j])) {
  523. String propertyName=PropertyHelper.getPropertyName(methods[j]);
  524. Object propertyValue=getValueFromProtocol(protocol, propertyName);
  525. if(propertyValue == null) { // if propertyValue is null, check if there is a we can use
  526. Property annotation=methods[j].getAnnotation(Property.class);
  527. // get the default value for the method- check for InetAddress types
  528. String defaultValue=null;
  529. if(InetAddressInfo.isInetAddressRelated(methods[j])) {
  530. defaultValue=ip_version == StackType.IPv4? annotation.defaultValueIPv4() : annotation.defaultValueIPv6();
  531. if(defaultValue != null && defaultValue.length() > 0) {
  532. Object converted=null;
  533. try {
  534. if(defaultValue.equalsIgnoreCase(Global.NON_LOOPBACK_ADDRESS))
  535. converted=default_ip_address;
  536. else
  537. converted=PropertyHelper.getConvertedValue(protocol, methods[j], properties, defaultValue, true);
  538. methods[j].invoke(protocol, converted);
  539. }
  540. catch(Exception e) {
  541. throw new Exception("default could not be assigned for method " + propertyName + " in "
  542. + protocolName + " with default " + defaultValue, e);
  543. }
  544. if(log.isDebugEnabled())
  545. log.debug("set property " + protocolName + "." + propertyName + " to default value " + converted);
  546. }
  547. }
  548. }
  549. }
  550. }
  551. //traverse class hierarchy and find all annotated fields and add them to the list if annotated
  552. Field[] fields=Util.getAllDeclaredFieldsWithAnnotations(protocol.getClass(), Property.class);
  553. for(int j=0; j < fields.length; j++) {
  554. String propertyName=PropertyHelper.getPropertyName(fields[j], properties);
  555. Object propertyValue=getValueFromProtocol(protocol, fields[j]);
  556. if(propertyValue == null) {
  557. // add to collection of @Properties with no user specified value
  558. Property annotation=fields[j].getAnnotation(Property.class);
  559. // get the default value for the field - check for InetAddress types
  560. String defaultValue=null;
  561. if(InetAddressInfo.isInetAddressRelated(protocol, fields[j])) {
  562. defaultValue=ip_version == StackType.IPv4? annotation.defaultValueIPv4() : annotation.defaultValueIPv6();
  563. if(defaultValue != null && defaultValue.length() > 0) {
  564. // condition for invoking converter
  565. if(defaultValue != null || !PropertyHelper.usesDefaultConverter(fields[j])) {
  566. Object converted=null;
  567. try {
  568. if(defaultValue.equalsIgnoreCase(Global.NON_LOOPBACK_ADDRESS))
  569. converted=default_ip_address;
  570. else
  571. converted=PropertyHelper.getConvertedValue(protocol, fields[j], properties, defaultValue, true);
  572. if(converted != null)
  573. setField(fields[j], protocol, converted);
  574. }
  575. catch(Exception e) {
  576. throw new Exception("default could not be assigned for field " + propertyName + " in "
  577. + protocolName + " with default value " + defaultValue, e);
  578. }
  579. if(log.isDebugEnabled())
  580. log.debug("set property " + protocolName + "." + propertyName + " to default value " + converted);
  581. }
  582. }
  583. }
  584. }
  585. }
  586. }
  587. }
  588. public static Object getValueFromProtocol(Protocol protocol, Field field) throws IllegalAccessException {
  589. if(protocol == null || field == null) return null;
  590. if(!Modifier.isPublic(field.getModifiers()))
  591. field.setAccessible(true);
  592. return field.get(protocol);
  593. }
  594. public static Object getValueFromProtocol(Protocol protocol, String field_name) throws IllegalAccessException {
  595. if(protocol == null || field_name == null) return null;
  596. Field field=Util.getField(protocol.getClass(), field_name);
  597. return field != null? getValueFromProtocol(protocol, field) : null;
  598. }
  599. /** Check whether any of the protocols 'below' provide evt_type */
  600. static boolean providesUpServices(Vector<ProtocolReq> req_list, int evt_type) {
  601. for (ProtocolReq pr:req_list){
  602. if(pr.providesUpService(evt_type))
  603. return true;
  604. }
  605. return false;
  606. }
  607. /** Checks whether any of the protocols 'above' provide evt_type */
  608. static boolean providesDownServices(Vector<ProtocolReq> req_list, int evt_type) {
  609. for (ProtocolReq pr:req_list){
  610. if(pr.providesDownService(evt_type))
  611. return true;
  612. }
  613. return false;
  614. }
  615. /**
  616. * This method creates a list of all properties (Field or Method) in dependency order,
  617. * where dependencies are specified using the dependsUpon specifier of the Property annotation.
  618. * In particular, it does the following:
  619. * (i) creates a master list of properties
  620. * (ii) checks that all dependency references are present
  621. * (iii) creates a copy of the master list in dependency order
  622. */
  623. static AccessibleObject[] computePropertyDependencies(Object obj, Map<String,String> properties) {
  624. // List of Fields and Methods of the protocol annotated with @Property
  625. List<AccessibleObject> unorderedFieldsAndMethods = new LinkedList<AccessibleObject>() ;
  626. List<AccessibleObject> orderedFieldsAndMethods = new LinkedList<AccessibleObject>() ;
  627. // Maps property name to property object
  628. Map<String, AccessibleObject> propertiesInventory = new HashMap<String, AccessibleObject>() ;
  629. // get the methods for this class and add them to the list if annotated with @Property
  630. Method[] methods=obj.getClass().getMethods();
  631. for(int i = 0; i < methods.length; i++) {
  632. if (methods[i].isAnnotationPresent(Property.class) && isSetPropertyMethod(methods[i])) {
  633. String propertyName = PropertyHelper.getPropertyName(methods[i]) ;
  634. unorderedFieldsAndMethods.add(methods[i]) ;
  635. propertiesInventory.put(propertyName, methods[i]) ;
  636. }
  637. }
  638. //traverse class hierarchy and find all annotated fields and add them to the list if annotated
  639. for(Class<?> clazz=obj.getClass(); clazz != null; clazz=clazz.getSuperclass()) {
  640. Field[] fields=clazz.getDeclaredFields();
  641. for(int i = 0; i < fields.length; i++ ) {
  642. if (fields[i].isAnnotationPresent(Property.class)) {
  643. String propertyName = PropertyHelper.getPropertyName(fields[i], properties) ;
  644. unorderedFieldsAndMethods.add(fields[i]) ;
  645. // may need to change this based on name parameter of Property
  646. propertiesInventory.put(propertyName, fields[i]) ;
  647. }
  648. }
  649. }
  650. // at this stage, we have all Fields and Methods annotated with @Property
  651. checkDependencyReferencesPresent(unorderedFieldsAndMethods, propertiesInventory) ;
  652. // order the fields and methods by dependency
  653. orderedFieldsAndMethods = orderFieldsAndMethodsByDependency(unorderedFieldsAndMethods, propertiesInventory) ;
  654. // convert to array of Objects
  655. AccessibleObject[] result = new AccessibleObject[orderedFieldsAndMethods.size()] ;
  656. for(int i = 0; i < orderedFieldsAndMethods.size(); i++) {
  657. result[i] = orderedFieldsAndMethods.get(i) ;
  658. }
  659. return result ;
  660. }
  661. static List<AccessibleObject> orderFieldsAndMethodsByDependency(List<AccessibleObject> unorderedList,
  662. Map<String, AccessibleObject> propertiesMap) {
  663. // Stack to detect cycle in depends relation
  664. Stack<AccessibleObject> stack = new Stack<AccessibleObject>() ;
  665. // the result list
  666. List<AccessibleObject> orderedList = new LinkedList<AccessibleObject>() ;
  667. // add the elements from the unordered list to the ordered list
  668. // any dependencies will be checked and added first, in recursive manner
  669. for(int i = 0; i < unorderedList.size(); i++) {
  670. AccessibleObject obj = unorderedList.get(i) ;
  671. addPropertyToDependencyList(orderedList, propertiesMap, stack, obj) ;
  672. }
  673. return orderedList ;
  674. }
  675. /**
  676. * DFS of dependency graph formed by Property annotations and dependsUpon parameter
  677. * This is used to create a list of Properties in dependency order
  678. */
  679. static void addPropertyToDependencyList(List<AccessibleObject> orderedList, Map<String, AccessibleObject> props, Stack<AccessibleObject> stack, AccessibleObject obj) {
  680. if (orderedList.contains(obj))
  681. return ;
  682. if (stack.search(obj) > 0) {
  683. throw new RuntimeException("Deadlock in @Property dependency processing") ;
  684. }
  685. // record the fact that we are processing obj
  686. stack.push(obj) ;
  687. // process dependencies for this object before adding it to the list
  688. Property annotation = obj.getAnnotation(Property.class) ;
  689. String dependsClause = annotation.dependsUpon() ;
  690. StringTokenizer st = new StringTokenizer(dependsClause, ",") ;
  691. while (st.hasMoreTokens()) {
  692. String token = st.nextToken().trim();
  693. AccessibleObject dep = props.get(token) ;
  694. // if null, throw exception
  695. addPropertyToDependencyList(orderedList, props, stack, dep) ;
  696. }
  697. // indicate we're done with processing dependencies
  698. stack.pop() ;
  699. // we can now add in dependency order
  700. orderedList.add(obj) ;
  701. }
  702. /*
  703. * Checks that for every dependency referred, there is a matching property
  704. */
  705. static void checkDependencyReferencesPresent(List<AccessibleObject> objects, Map<String, AccessibleObject> props) {
  706. // iterate overall properties marked by @Property
  707. for(int i = 0; i < objects.size(); i++) {
  708. // get the Property annotation
  709. AccessibleObject ao = objects.get(i) ;
  710. Property annotation = ao.getAnnotation(Property.class) ;
  711. if (annotation == null) {
  712. throw new IllegalArgumentException("@Property annotation is required for checking dependencies;" +
  713. " annotation is missing for Field/Method " + ao.toString()) ;
  714. }
  715. String dependsClause = annotation.dependsUpon() ;
  716. if (dependsClause.trim().length() == 0)
  717. continue ;
  718. // split dependsUpon specifier into tokens; trim each token; search for token in list
  719. StringTokenizer st = new StringTokenizer(dependsClause, ",") ;
  720. while (st.hasMoreTokens()) {
  721. String token = st.nextToken().trim() ;
  722. // check that the string representing a property name is in the list
  723. boolean found = false ;
  724. Set<String> keyset = props.keySet();
  725. for (Iterator<String> iter = keyset.iterator(); iter.hasNext();) {
  726. if (iter.next().equals(token)) {
  727. found = true ;
  728. break ;
  729. }
  730. }
  731. if (!found) {
  732. throw new IllegalArgumentException("@Property annotation " + annotation.name() +
  733. " has an unresolved dependsUpon property: " + token) ;
  734. }
  735. }
  736. }
  737. }
  738. public static void resolveAndInvokePropertyMethods(Object obj, Map<String,String> props) throws Exception {
  739. Method[] methods=obj.getClass().getMethods();
  740. for(Method method: methods) {
  741. resolveAndInvokePropertyMethod(obj, method, props) ;
  742. }
  743. }
  744. public static void resolveAndInvokePropertyMethod(Object obj, Method method, Map<String,String> props) throws Exception {
  745. String methodName=method.getName();
  746. Property annotation=method.getAnnotation(Property.class);
  747. if(annotation != null && isSetPropertyMethod(method)) {
  748. String propertyName=PropertyHelper.getPropertyName(method) ;
  749. String propertyValue=props.get(propertyName);
  750. // if there is a systemProperty attribute defined in the annotation, set the property value from the system property
  751. String tmp=grabSystemProp(method.getAnnotation(Property.class));
  752. if(tmp != null)
  753. propertyValue=tmp;
  754. if(propertyName != null && propertyValue != null) {
  755. String deprecated_msg=annotation.deprecatedMessage();
  756. if(deprecated_msg != null && deprecated_msg.length() > 0) {
  757. log.warn(method.getDeclaringClass().getSimpleName() + "." + methodName + ": " + deprecated_msg);
  758. }
  759. }
  760. if(propertyValue != null) {
  761. Object converted=null;
  762. try {
  763. converted=PropertyHelper.getConvertedValue(obj, method, props, propertyValue, true);
  764. method.invoke(obj, converted);
  765. }
  766. catch(Exception e) {
  767. String name=obj instanceof Protocol? ((Protocol)obj).getName() : obj.getClass().getName();
  768. throw new Exception("Could not assign property " + propertyName + " in "
  769. + name + ", method is " + methodName + ", converted value is " + converted, e);
  770. }
  771. }
  772. props.remove(propertyName);
  773. }
  774. }
  775. public static void resolveAndAssignFields(Object obj, Map<String,String> props) throws Exception {
  776. //traverse class hierarchy and find all annotated fields
  777. for(Class<?> clazz=obj.getClass(); clazz != null; clazz=clazz.getSuperclass()) {
  778. Field[] fields=clazz.getDeclaredFields();
  779. for(Field field: fields) {
  780. resolveAndAssignField(obj, field, props) ;
  781. }
  782. }
  783. }
  784. public static void resolveAndAssignField(Object obj, Field field, Map<String,String> props) throws Exception {
  785. Property annotation=field.getAnnotation(Property.class);
  786. if(annotation != null) {
  787. String propertyName = PropertyHelper.getPropertyName(field, props) ;
  788. String propertyValue=props.get(propertyName);
  789. // if there is a systemProperty attribute defined in the annotation, set the property value from the system property
  790. String tmp=grabSystemProp(field.getAnnotation(Property.class));
  791. if(tmp != null)
  792. propertyValue=tmp;
  793. if(propertyName != null && propertyValue != null) {
  794. String deprecated_msg=annotation.deprecatedMessage();
  795. if(deprecated_msg != null && deprecated_msg.length() > 0) {
  796. log.warn(field.getDeclaringClass().getSimpleName() + "." + field.getName() + ": " + deprecated_msg);
  797. }
  798. }
  799. if(propertyValue != null || !PropertyHelper.usesDefaultConverter(field)){
  800. Object converted=null;
  801. try {
  802. converted=PropertyHelper.getConvertedValue(obj, field, props, propertyValue, true);
  803. if(converted != null)
  804. setField(field, obj, converted);
  805. }
  806. catch(Exception e) {
  807. String name=obj instanceof Protocol? ((Protocol)obj).getName() : obj.getClass().getName();
  808. throw new Exception("Property assignment of " + propertyName + " in "
  809. + name + " with original property value " + propertyValue + " and converted to " + converted
  810. + " could not be assigned", e);
  811. }
  812. }
  813. props.remove(propertyName);
  814. }
  815. }
  816. public static void removeDeprecatedProperties(Object obj, Map<String,String> props) throws Exception {
  817. //traverse class hierarchy and find all deprecated properties
  818. for(Class<?> clazz=obj.getClass(); clazz != null; clazz=clazz.getSuperclass()) {
  819. if(clazz.isAnnotationPresent(DeprecatedProperty.class)) {
  820. DeprecatedProperty declaredAnnotation=clazz.getAnnotation(DeprecatedProperty.class);
  821. String[] deprecatedProperties=declaredAnnotation.names();
  822. for(String propertyName : deprecatedProperties) {
  823. String propertyValue=props.get(propertyName);
  824. if(propertyValue != null) {
  825. if(log.isWarnEnabled()) {
  826. String name=obj instanceof Protocol? ((Protocol)obj).getName() : obj.getClass().getName();
  827. log.warn(name + " property " + propertyName + " was deprecated and is ignored");
  828. }
  829. props.remove(propertyName);
  830. }
  831. }
  832. }
  833. }
  834. }
  835. public static boolean isSetPropertyMethod(Method method) {
  836. return (method.getName().startsWith("set") &&
  837. method.getReturnType() == java.lang.Void.TYPE &&
  838. method.getParameterTypes().length == 1);
  839. }
  840. public static void setField(Field field, Object target, Object value) {
  841. if(!Modifier.isPublic(field.getModifiers())) {
  842. field.setAccessible(true);
  843. }
  844. try {
  845. field.set(target, value);
  846. }
  847. catch(IllegalAccessException iae) {
  848. throw new IllegalArgumentException("Could not set field " + field, iae);
  849. }
  850. }
  851. public static Object getField(Field field, Object target) {
  852. if(!Modifier.isPublic(field.getModifiers())) {
  853. field.setAccessible(true);
  854. }
  855. try {
  856. return field.get(target);
  857. }
  858. catch(IllegalAccessException iae) {
  859. throw new IllegalArgumentException("Could not get field " + field, iae);
  860. }
  861. }
  862. private static String grabSystemProp(Property annotation) {
  863. String[] system_property_names=annotation.systemProperty();
  864. String retval=null;
  865. for(String system_property_name: system_property_names) {
  866. if(system_property_name != null && system_property_name.length() > 0) {
  867. if(system_property_name.equals(Global.BIND_ADDR) || system_property_name.equals(Global.BIND_ADDR_OLD))
  868. if(Util.isBindAddressPropertyIgnored())
  869. continue;
  870. try {
  871. retval=System.getProperty(system_property_name);
  872. if(retval != null)
  873. return retval;
  874. }
  875. catch(SecurityException ex) {
  876. log.error("failed getting system property for " + system_property_name, ex);
  877. }
  878. }
  879. }
  880. return retval;
  881. }
  882. /* --------------------------- End of Private Methods ---------------------------------- */
  883. private static class ProtocolReq {
  884. final Vector<Integer> up_reqs=new Vector<Integer>();
  885. final Vector<Integer> down_reqs=new Vector<Integer>();
  886. final Vector<Integer> up_provides=new Vector<Integer>();
  887. final Vector<Integer> down_provides=new Vector<Integer>();
  888. final String name;
  889. ProtocolReq(Protocol p) {
  890. this.name=p.getName();
  891. if(p.requiredUpServices() != null) {
  892. up_reqs.addAll(p.requiredUpServices());
  893. }
  894. if(p.requiredDownServices() != null) {
  895. down_reqs.addAll(p.requiredDownServices());
  896. }
  897. if(p.providedUpServices() != null) {
  898. up_provides.addAll(p.providedUpServices());
  899. }
  900. if(p.providedDownServices() != null) {
  901. down_provides.addAll(p.providedDownServices());
  902. }
  903. }
  904. boolean providesUpService(int evt_type) {
  905. for(Integer type:up_provides) {
  906. if(type == evt_type)
  907. return true;
  908. }
  909. return false;
  910. }
  911. boolean providesDownService(int evt_type) {
  912. for(Integer type:down_provides) {
  913. if(type == evt_type)
  914. return true;
  915. }
  916. return false;
  917. }
  918. public String toString() {
  919. StringBuilder ret=new StringBuilder();
  920. ret.append('\n' + name + ':');
  921. if(!up_reqs.isEmpty())
  922. ret.append("\nRequires from above: " + printUpReqs());
  923. if(!down_reqs.isEmpty())
  924. ret.append("\nRequires from below: " + printDownReqs());
  925. if(!up_provides.isEmpty())
  926. ret.append("\nProvides to above: " + printUpProvides());
  927. if(!down_provides.isEmpty())
  928. ret.append("\nProvides to below: ").append(printDownProvides());
  929. return ret.toString();
  930. }
  931. String printUpReqs() {
  932. StringBuilder ret;
  933. ret=new StringBuilder("[");
  934. for(Integer type:up_reqs) {
  935. ret.append(Event.type2String(type) + ' ');
  936. }
  937. return ret.toString() + ']';
  938. }
  939. String printDownReqs() {
  940. StringBuilder ret=new StringBuilder("[");
  941. for(Integer type:down_reqs) {
  942. ret.append(Event.type2String(type) + ' ');
  943. }
  944. return ret.toString() + ']';
  945. }
  946. String printUpProvides() {
  947. StringBuilder ret=new StringBuilder("[");
  948. for(Integer type:up_provides) {
  949. ret.append(Event.type2String(type) + ' ');
  950. }
  951. return ret.toString() + ']';
  952. }
  953. String printDownProvides() {
  954. StringBuilder ret=new StringBuilder("[");
  955. for(Integer type:down_provides) {
  956. ret.append(Event.type2String(type) + ' ');
  957. }
  958. return ret.toString() + ']';
  959. }
  960. }
  961. /**
  962. * Parses and encapsulates the specification for 1 protocol of the protocol stack, e.g.
  963. * <code>UNICAST(timeout=5000)</code>
  964. */
  965. public static class ProtocolConfiguration {
  966. private final String protocol_name;
  967. private String properties_str;
  968. private final Map<String,String> properties=new HashMap<String,String>();
  969. private static final String protocol_prefix="org.jgroups.protocols";
  970. /**
  971. * Creates a new ProtocolConfiguration.
  972. * @param config_str The configuration specification for the protocol, e.g.
  973. * <pre>VERIFY_SUSPECT(timeout=1500)</pre>
  974. */
  975. public ProtocolConfiguration(String config_str) throws Exception {
  976. int index=config_str.indexOf('('); // e.g. "UDP(in_port=3333)"
  977. int end_index=config_str.lastIndexOf(')');
  978. if(index == -1) {
  979. protocol_name=config_str;
  980. properties_str="";
  981. }
  982. else {
  983. if(end_index == -1) {
  984. throw new Exception("Configurator.ProtocolConfiguration(): closing ')' " +
  985. "not found in " + config_str + ": properties cannot be set !");
  986. }
  987. else {
  988. properties_str=config_str.substring(index + 1, end_index);
  989. protocol_name=config_str.substring(0, index);