/src/ibis/smartsockets/direct/Preference.java

https://github.com/interdroid/smartsockets · Java · 360 lines · 243 code · 84 blank · 33 comment · 58 complexity · c56405627f9620ddb588d830115d1fa9 MD5 · raw file

  1. /**
  2. *
  3. */
  4. package ibis.smartsockets.direct;
  5. import ibis.smartsockets.util.NetworkUtils;
  6. import java.net.InetAddress;
  7. import java.net.InetSocketAddress;
  8. import java.util.ArrayList;
  9. import org.slf4j.Logger;
  10. import org.slf4j.LoggerFactory;
  11. class Preference {
  12. private static final Logger logger =
  13. LoggerFactory.getLogger("ibis.smartsockets.network.preference");
  14. private final String name;
  15. private final boolean strict;
  16. private ArrayList<Network> preferences = new ArrayList<Network>();
  17. private boolean noneAllowed = false;
  18. private boolean siteUsed = false;
  19. private boolean linkUsed = false;
  20. private boolean globalUsed = false;
  21. Preference(String name, boolean strict) {
  22. this.name = name;
  23. this.strict = strict;
  24. }
  25. int size() {
  26. return preferences.size();
  27. }
  28. void addSite() {
  29. if (siteUsed) {
  30. logger.warn("Preference(" + name + "): "
  31. + "Site addresses already used.");
  32. throw new IllegalStateException(name + ": Site addresses "
  33. + "already used.");
  34. }
  35. if (noneAllowed) {
  36. logger.warn("Preference(" + name + "): "
  37. + "Cannot combine network rule 'site' with rule 'none'!");
  38. throw new IllegalStateException(name + ": Cannot combine network " +
  39. "rule 'site' with rule 'none'!");
  40. }
  41. if (logger.isDebugEnabled()) {
  42. logger.debug("Preference(" + name
  43. + "): Adding site-local addresses to "
  44. + "connection preference");
  45. }
  46. preferences.add(Network.SITE);
  47. siteUsed = true;
  48. }
  49. void addLink() {
  50. if (linkUsed) {
  51. logger.warn("Preference(" + name + "): "
  52. + "Link addresses already used.");
  53. throw new IllegalStateException(name + ": Link addresses "
  54. + "already used.");
  55. }
  56. if (noneAllowed) {
  57. logger.warn("Preference(" + name + "): "
  58. + "Cannot combine network rule 'link' with rule 'none'!");
  59. throw new IllegalStateException(name + ": Cannot combine network " +
  60. "rule 'link' with rule 'none'!");
  61. }
  62. if (logger.isDebugEnabled()) {
  63. logger.debug("Preference(" + name + "): Adding "
  64. + "link-local addresses to connection preference");
  65. }
  66. preferences.add(Network.LINK);
  67. linkUsed = true;
  68. }
  69. void addGlobal() {
  70. if (noneAllowed) {
  71. logger.warn("Preference(" + name + "): "
  72. + "Cannot combine network rule 'global' with rule 'none'!");
  73. throw new IllegalStateException(name + ": Cannot combine network " +
  74. "rule 'global' with rule 'none'!");
  75. }
  76. if (globalUsed) {
  77. logger.warn("Preference(" + name + "): "
  78. + "Global addresses already used.");
  79. throw new IllegalStateException(name + ": Global addresses "
  80. + "already used.");
  81. }
  82. if (logger.isDebugEnabled()) {
  83. logger.debug("Preference(" + name + "): "
  84. + "Adding global addresses to connection preference");
  85. }
  86. preferences.add(Network.GLOBAL);
  87. globalUsed = true;
  88. }
  89. public void addNone() {
  90. if (siteUsed || linkUsed || globalUsed) {
  91. logger.warn("Preference(" + name + "): "
  92. + "Cannot combine network rule 'none' with any rules that " +
  93. "allow connection!");
  94. throw new IllegalStateException(name + ": network rule 'none' " +
  95. "specified, while other rules already apply!.");
  96. }
  97. preferences.add(Network.NONE);
  98. noneAllowed = true;
  99. }
  100. void addNetwork(Network nw) {
  101. if (noneAllowed) {
  102. logger.warn("Preference(" + name + "): "
  103. + "Cannot combine network rule with rule 'none'!");
  104. throw new IllegalStateException(name + ": Cannot combine network " +
  105. "rule with rule 'none'!");
  106. }
  107. if (logger.isDebugEnabled()) {
  108. logger.debug("Preference(" + name + "): "
  109. + "Adding network " + nw + " to connection preference");
  110. }
  111. preferences.add(nw);
  112. }
  113. /*
  114. void addNetwork(byte[] network, byte[] mask) {
  115. if (logger.isDebugEnabled()) {
  116. logger.debug("Preference(" + name + "): "
  117. + "Adding network " + NetworkUtils.bytesToString(network)
  118. + "/" + NetworkUtils.bytesToString(mask)
  119. + " to connection preference");
  120. }
  121. preferences.add(new Network(network, mask));
  122. }
  123. */
  124. private int score(InetAddress ad) {
  125. int score = 0;
  126. for (Network nw : preferences) {
  127. if (nw.match(ad)) {
  128. return score;
  129. } else {
  130. score++;
  131. }
  132. }
  133. return score + 1;
  134. }
  135. private void sort(Object[] objects, int[] scores) {
  136. for (int i = 0; i < objects.length - 1; i++) {
  137. for (int j = 0; j < objects.length - 1 - i; j++) {
  138. if (scores[j + 1] < scores[j]) {
  139. int tmp = scores[j + 1];
  140. scores[j + 1] = scores[j];
  141. scores[j] = tmp;
  142. Object ta = objects[j + 1];
  143. objects[j + 1] = objects[j];
  144. objects[j] = ta;
  145. }
  146. }
  147. }
  148. }
  149. InetSocketAddress[] sort(InetSocketAddress[] ads, boolean inPlace) {
  150. // TODO: New implementation here ?
  151. // The global/local/link differences should now be trivial, so many
  152. // of the simpler rules can be implemented more efficiently....
  153. // Nothing to if there are no rules, or only 1 address....
  154. if (preferences.size() == 0 || ads.length == 1) {
  155. if (logger.isDebugEnabled()) {
  156. logger.debug("Preference(" + name + "):"
  157. + " No sorting required");
  158. }
  159. return ads;
  160. }
  161. // First give every address a score based on the preference rules.
  162. // Also count the number of entries that got a real score.
  163. int scored = 0;
  164. int[] scores = new int[ads.length];
  165. for (int i = 0; i < ads.length; i++) {
  166. scores[i] = score(ads[i].getAddress());
  167. if (scores[i] < preferences.size() + 1) {
  168. scored++;
  169. }
  170. }
  171. InetSocketAddress[] result = null;
  172. if (strict && !inPlace) {
  173. // We now remove all the addresses which are not wanted.
  174. result = new InetSocketAddress[scored];
  175. int[] tmp = new int[scored];
  176. int next = 0;
  177. if (logger.isInfoEnabled()) {
  178. logger.info("Preference(" + name + "): Strict "
  179. + "mode on. Removing unwanted addresses.");
  180. }
  181. for (int i = 0; i < ads.length; i++) {
  182. if (scores[i] < preferences.size() + 1) {
  183. result[next] = ads[i];
  184. tmp[next] = scores[i];
  185. next++;
  186. } else {
  187. if (logger.isInfoEnabled()) {
  188. logger.info("Preference(" + name + "): "
  189. + "Removing address: "
  190. + NetworkUtils.ipToString(ads[i].getAddress()));
  191. }
  192. }
  193. }
  194. scores = tmp;
  195. } else if (!inPlace) {
  196. // When we do not want inplace sorting, we copy the addresses.
  197. result = ads.clone();
  198. } else {
  199. // Else, we use the addresses directly.
  200. result = ads;
  201. }
  202. // Once every one has a score, we'll bubble sort the lot.
  203. sort(result, scores);
  204. return result;
  205. }
  206. InetAddress[] sort(InetAddress[] ads, boolean inPlace) {
  207. // Nothing to if there are no rules, or only 1 address....
  208. if (preferences.size() == 0 || ads.length == 1) {
  209. if (logger.isDebugEnabled()) {
  210. logger.debug("Preference(" + name + "): "
  211. + "No sorting required");
  212. }
  213. return ads;
  214. }
  215. // First give every address a score based on the preference rules.
  216. // Also count the number of entries that got a real score.
  217. int scored = 0;
  218. int[] scores = new int[ads.length];
  219. for (int i = 0; i < ads.length; i++) {
  220. scores[i] = score(ads[i]);
  221. if (scores[i] < preferences.size() + 1) {
  222. scored++;
  223. }
  224. }
  225. InetAddress[] result = null;
  226. if (strict && !inPlace) {
  227. // We now remove all the addresses which are not wanted.
  228. if (logger.isInfoEnabled()) {
  229. logger.info("Preference(" + name + "): "
  230. + "Strict mode on. Removing unwanted addresses.");
  231. }
  232. result = new InetAddress[scored];
  233. int[] tmp = new int[scored];
  234. int next = 0;
  235. for (int i = 0; i < ads.length; i++) {
  236. if (scores[i] < preferences.size() + 1) {
  237. result[next] = ads[i];
  238. tmp[next] = scores[i];
  239. next++;
  240. } else {
  241. if (logger.isInfoEnabled()) {
  242. logger.info("Preference(" + name + "): "
  243. + "Removing address: "
  244. + NetworkUtils.ipToString(ads[i]));
  245. }
  246. }
  247. }
  248. scores = tmp;
  249. } else if (!inPlace) {
  250. // When we do not want inplace sorting, we copy the addresses.
  251. result = ads.clone();
  252. } else {
  253. // Else, we use the addresses directly.
  254. result = ads;
  255. }
  256. // Once every one has a score, we'll bubble sort the lot.
  257. sort(result, scores);
  258. return result;
  259. }
  260. public String toString() {
  261. if (preferences.size() == 0) {
  262. return name + ": Connection preference: none";
  263. }
  264. StringBuffer buf = new StringBuffer(name + ": Connection preference:");
  265. int i = 0;
  266. for (Network nw : preferences) {
  267. buf.append(nw.toString());
  268. if (++i < preferences.size()) {
  269. buf.append(",");
  270. }
  271. }
  272. return buf.toString();
  273. }
  274. }