PageRenderTime 205ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/controller/src/main/java/org/jboss/as/controller/interfaces/ParsedInterfaceCriteria.java

https://github.com/smcgowan/wildfly
Java | 327 lines | 265 code | 29 blank | 33 comment | 52 complexity | 2513ac2cbbeb196529549bb96d355708 MD5 | raw file
  1. /*
  2. * JBoss, Home of Professional Open Source.
  3. * Copyright 2011, Red Hat, Inc., and individual contributors
  4. * as indicated by the @author tags. See the copyright.txt file in the
  5. * distribution for a full listing of individual contributors.
  6. *
  7. * This is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation; either version 2.1 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This software is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this software; if not, write to the Free
  19. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  21. */
  22. package org.jboss.as.controller.interfaces;
  23. import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
  24. import static org.jboss.as.controller.ControllerLogger.SERVER_LOGGER;
  25. import static org.jboss.as.controller.ControllerMessages.MESSAGES;
  26. import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ANY_ADDRESS;
  27. import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ANY_IPV4_ADDRESS;
  28. import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ANY_IPV6_ADDRESS;
  29. import java.net.InetAddress;
  30. import java.net.UnknownHostException;
  31. import java.util.HashSet;
  32. import java.util.List;
  33. import java.util.Set;
  34. import java.util.regex.Pattern;
  35. import java.util.regex.PatternSyntaxException;
  36. import org.jboss.as.controller.parsing.Element;
  37. import org.jboss.as.controller.parsing.ParseUtils;
  38. import org.jboss.dmr.ModelNode;
  39. import org.jboss.dmr.ModelType;
  40. import org.jboss.dmr.Property;
  41. /**
  42. * Utility class to create a interface criteria based on a {@link ModelNode} description
  43. *
  44. * @author Brian Stansberry
  45. * @author Emanuel Muckenhuber
  46. */
  47. public final class ParsedInterfaceCriteria {
  48. private static final ParsedInterfaceCriteria EMPTY = new ParsedInterfaceCriteria();
  49. private static final ParsedInterfaceCriteria ANY = new ParsedInterfaceCriteria(false, false, true);
  50. private static final ParsedInterfaceCriteria V4 = new ParsedInterfaceCriteria(true, false, false);
  51. private static final ParsedInterfaceCriteria V6 = new ParsedInterfaceCriteria(false, true, false);
  52. private final String failureMessage;
  53. private final boolean anyLocalV4;
  54. private final boolean anyLocalV6;
  55. private final boolean anyLocal;
  56. private final Set<InterfaceCriteria> criteria = new HashSet<InterfaceCriteria>();
  57. private ParsedInterfaceCriteria() {
  58. this.failureMessage = null;
  59. this.anyLocal = anyLocalV4 = anyLocalV6 = false;
  60. }
  61. private ParsedInterfaceCriteria(final String failureMessage) {
  62. this.failureMessage = failureMessage;
  63. this.anyLocal = anyLocalV4 = anyLocalV6 = false;
  64. }
  65. private ParsedInterfaceCriteria(final boolean anyLocalV4, final boolean anyLocalV6, final boolean anyLocal) {
  66. this.failureMessage = null;
  67. this.anyLocal = anyLocal;
  68. this.anyLocalV4 = anyLocalV4;
  69. this.anyLocalV6 = anyLocalV6;
  70. }
  71. private ParsedInterfaceCriteria(final Set<InterfaceCriteria> criteria) {
  72. this.failureMessage = null;
  73. this.anyLocal = anyLocalV4 = anyLocalV6 = false;
  74. this.criteria.addAll(criteria);
  75. }
  76. public String getFailureMessage() {
  77. return failureMessage;
  78. }
  79. public boolean isAnyLocalV4() {
  80. return anyLocalV4;
  81. }
  82. public boolean isAnyLocalV6() {
  83. return anyLocalV6;
  84. }
  85. public boolean isAnyLocal() {
  86. return anyLocal;
  87. }
  88. public Set<InterfaceCriteria> getCriteria() {
  89. return criteria;
  90. }
  91. public static ParsedInterfaceCriteria parse(final ModelNode criteria) {
  92. return parse(criteria, true);
  93. }
  94. public static ParsedInterfaceCriteria parse(final ModelNode model, boolean specified) {
  95. if (model.getType() != ModelType.OBJECT) {
  96. return new ParsedInterfaceCriteria(MESSAGES.illegalInterfaceCriteria(model.getType(), ModelType.OBJECT));
  97. }
  98. // Remove operation params
  99. final ModelNode subModel = model.clone();
  100. subModel.remove(ModelDescriptionConstants.OP);
  101. subModel.remove(ModelDescriptionConstants.OP_ADDR);
  102. final ParsedInterfaceCriteria parsed;
  103. if(subModel.hasDefined(ANY_ADDRESS) && subModel.get(ANY_ADDRESS).asBoolean(false)) {
  104. parsed = ParsedInterfaceCriteria.ANY;
  105. } else if(subModel.hasDefined(ANY_IPV4_ADDRESS) && subModel.get(ANY_IPV4_ADDRESS).asBoolean(false)) {
  106. parsed = ParsedInterfaceCriteria.V4;
  107. } else if(subModel.hasDefined(ANY_IPV6_ADDRESS) && subModel.get(ANY_IPV6_ADDRESS).asBoolean(false)) {
  108. parsed = ParsedInterfaceCriteria.V6;
  109. } else {
  110. try {
  111. final List<Property> nodes = subModel.asPropertyList();
  112. final Set<InterfaceCriteria> criteriaSet = new HashSet<InterfaceCriteria>();
  113. for (final Property property : nodes) {
  114. final InterfaceCriteria criterion = parseCriteria(property, false);
  115. if(criterion == null) {
  116. // Ignore empty criteria
  117. continue;
  118. } else if (criterion instanceof WildcardInetAddressInterfaceCriteria) {
  119. // AS7-1668: stop processing and just return the any binding.
  120. if (nodes.size() > 1) {
  121. SERVER_LOGGER.wildcardAddressDetected();
  122. }
  123. WildcardInetAddressInterfaceCriteria wc = (WildcardInetAddressInterfaceCriteria) criterion;
  124. switch(wc.getVersion()) {
  125. case V4: return ParsedInterfaceCriteria.V4;
  126. case V6: return ParsedInterfaceCriteria.V6;
  127. default: return ParsedInterfaceCriteria.ANY;
  128. }
  129. }
  130. else {
  131. criteriaSet.add(criterion);
  132. }
  133. }
  134. parsed = new ParsedInterfaceCriteria(criteriaSet);
  135. } catch (ParsingException p) {
  136. return new ParsedInterfaceCriteria(p.msg);
  137. }
  138. }
  139. if (specified && parsed.getFailureMessage() == null && ! parsed.isAnyLocal() && ! parsed.isAnyLocalV4()
  140. && ! parsed.isAnyLocalV6() && parsed.getCriteria().size() == 0) {
  141. return new ParsedInterfaceCriteria(MESSAGES.noInterfaceCriteria());
  142. }
  143. return parsed;
  144. }
  145. private static InterfaceCriteria parseCriteria(final Property property, final boolean nested) {
  146. final Element element = Element.forName(property.getName());
  147. switch (element) {
  148. case LINK_LOCAL_ADDRESS:
  149. return LinkLocalInterfaceCriteria.INSTANCE;
  150. case LOOPBACK:
  151. return LoopbackInterfaceCriteria.INSTANCE;
  152. case MULTICAST:
  153. return SupportsMulticastInterfaceCriteria.INSTANCE;
  154. case POINT_TO_POINT:
  155. return PointToPointInterfaceCriteria.INSTANCE;
  156. case PUBLIC_ADDRESS:
  157. return PublicAddressInterfaceCriteria.INSTANCE;
  158. case SITE_LOCAL_ADDRESS:
  159. return SiteLocalInterfaceCriteria.INSTANCE;
  160. case UP:
  161. return UpInterfaceCriteria.INSTANCE;
  162. case VIRTUAL:
  163. return VirtualInterfaceCriteria.INSTANCE;
  164. case INET_ADDRESS: {
  165. ModelNode value = property.getValue();
  166. value = parsePossibleExpression(value);
  167. checkStringType(value, element.getLocalName(), true);
  168. return createInetAddressCriteria(property.getValue());
  169. }
  170. case LOOPBACK_ADDRESS: {
  171. ModelNode value = property.getValue();
  172. value = parsePossibleExpression(value);
  173. checkStringType(value, element.getLocalName(), true);
  174. return new LoopbackAddressInterfaceCriteria(property.getValue());
  175. }
  176. case NIC: {
  177. checkStringType(property.getValue(), element.getLocalName());
  178. return new NicInterfaceCriteria(property.getValue().asString());
  179. }
  180. case NIC_MATCH: {
  181. checkStringType(property.getValue(), element.getLocalName());
  182. return createNicMatchCriteria(property.getValue());
  183. }
  184. case SUBNET_MATCH: {
  185. return createSubnetMatchCriteria(property.getValue());
  186. }
  187. case ANY:
  188. case NOT:
  189. if(nested) {
  190. throw new ParsingException(MESSAGES.nestedElementNotAllowed(element));
  191. }
  192. return parseNested(property.getValue(), element == Element.ANY);
  193. default:
  194. throw new ParsingException(MESSAGES.unknownCriteriaInterfaceType(property.getName()));
  195. }
  196. }
  197. private static InterfaceCriteria parseNested(final ModelNode subModel, final boolean any) {
  198. if(!subModel.isDefined() || subModel.asInt() == 0) {
  199. return null;
  200. }
  201. final Set<InterfaceCriteria> criteriaSet = new HashSet<InterfaceCriteria>();
  202. for(final Property nestedProperty : subModel.asPropertyList()) {
  203. final Element element = Element.forName(nestedProperty.getName());
  204. switch (element) {
  205. case INET_ADDRESS:
  206. case NIC :
  207. case NIC_MATCH:
  208. case SUBNET_MATCH: {
  209. if (nestedProperty.getValue().getType() == ModelType.LIST) {
  210. for (ModelNode item : nestedProperty.getValue().asList()) {
  211. Property prop = new Property(nestedProperty.getName(), item);
  212. InterfaceCriteria itemCriteria = parseCriteria(prop, true);
  213. if(itemCriteria != null) {
  214. criteriaSet.add(itemCriteria);
  215. }
  216. }
  217. break;
  218. } // else drop down into default: block
  219. }
  220. default: {
  221. final InterfaceCriteria criteria = parseCriteria(nestedProperty, true);
  222. if(criteria != null) {
  223. criteriaSet.add(criteria);
  224. }
  225. }
  226. }
  227. }
  228. if(criteriaSet.isEmpty()) {
  229. return null;
  230. }
  231. return any ? new AnyInterfaceCriteria(criteriaSet) : new NotInterfaceCriteria(criteriaSet);
  232. }
  233. private static InterfaceCriteria createInetAddressCriteria(final ModelNode model) throws ParsingException {
  234. try {
  235. String rawAddress = model.resolve().asString();
  236. InetAddress address = InetAddress.getByName(rawAddress);
  237. if (address.isAnyLocalAddress()) {
  238. // they've entered a wildcard address
  239. return new WildcardInetAddressInterfaceCriteria(address);
  240. } else {
  241. return new InetAddressMatchInterfaceCriteria(model);
  242. }
  243. } catch (UnknownHostException e) {
  244. throw new ParsingException(MESSAGES.invalidAddress(model.asString(),
  245. e.getLocalizedMessage()));
  246. }
  247. }
  248. private static InterfaceCriteria createNicMatchCriteria(final ModelNode model) throws ParsingException {
  249. try {
  250. Pattern pattern = Pattern.compile(model.asString());
  251. return new NicMatchInterfaceCriteria(pattern);
  252. } catch (PatternSyntaxException e) {
  253. throw new ParsingException(MESSAGES.invalidInterfaceCriteriaPattern(model.asString(),
  254. Element.NIC_MATCH.getLocalName()));
  255. }
  256. }
  257. private static InterfaceCriteria createSubnetMatchCriteria(final ModelNode model) throws ParsingException {
  258. String value;
  259. String[] split = null;
  260. try {
  261. value = model.asString();
  262. split = value.split("/");
  263. if (split.length != 2) {
  264. throw new ParsingException(MESSAGES.invalidAddressMaskValue(value));
  265. }
  266. // todo - possible DNS hit here
  267. final InetAddress addr = InetAddress.getByName(split[0]);
  268. // Validate both parts of the split
  269. final byte[] net = addr.getAddress();
  270. final int mask = Integer.parseInt(split[1]);
  271. return new SubnetMatchInterfaceCriteria(net, mask);
  272. } catch (final ParsingException e) {
  273. throw e;
  274. } catch (final NumberFormatException e) {
  275. throw new ParsingException(MESSAGES.invalidAddressMask(split[1], e.getLocalizedMessage()));
  276. } catch (final UnknownHostException e) {
  277. throw new ParsingException(MESSAGES.invalidAddressValue(split[0], e.getLocalizedMessage()));
  278. }
  279. }
  280. private static void checkStringType(ModelNode node, String id) {
  281. checkStringType(node, id, false);
  282. }
  283. private static void checkStringType(ModelNode node, String id, boolean allowExpressions) {
  284. if (node.getType() != ModelType.STRING && (!allowExpressions || node.getType() != ModelType.EXPRESSION)) {
  285. throw new ParsingException(MESSAGES.illegalValueForInterfaceCriteria(node.getType(), id, ModelType.STRING));
  286. }
  287. }
  288. private static ModelNode parsePossibleExpression(final ModelNode node) {
  289. return (node.getType() == ModelType.STRING) ? ParseUtils.parsePossibleExpression(node.asString()) : node;
  290. }
  291. private static class ParsingException extends RuntimeException {
  292. private static final long serialVersionUID = -5627251228393035383L;
  293. private final String msg;
  294. private ParsingException(String msg) {
  295. this.msg = msg;
  296. }
  297. }
  298. }