PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/servers/sip-presence/presence/server/subscription-sbb/src/main/java/org/mobicents/slee/sippresence/server/subscription/rules/RulesetProcessor.java

http://mobicents.googlecode.com/
Java | 559 lines | 380 code | 30 blank | 149 comment | 135 complexity | a5ede3a706b4385d258da263984b8a3f MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0, LGPL-2.1, GPL-2.0, CC-BY-SA-3.0, CC0-1.0, Apache-2.0, BSD-3-Clause
  1. /*
  2. * JBoss, Home of Professional Open Source
  3. * Copyright 2011, Red Hat, Inc. and individual contributors
  4. * by the @authors tag. See the copyright.txt in the distribution for a
  5. * 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.mobicents.slee.sippresence.server.subscription.rules;
  23. import java.util.GregorianCalendar;
  24. import java.util.HashSet;
  25. import java.util.Iterator;
  26. import java.util.List;
  27. import java.util.Set;
  28. import javax.xml.bind.JAXBElement;
  29. import javax.xml.datatype.DatatypeConfigurationException;
  30. import javax.xml.datatype.DatatypeFactory;
  31. import javax.xml.datatype.XMLGregorianCalendar;
  32. import org.openxdm.xcap.client.appusage.presrules.jaxb.ProvideAllAttributes;
  33. import org.openxdm.xcap.client.appusage.presrules.jaxb.ProvideDevicePermission;
  34. import org.openxdm.xcap.client.appusage.presrules.jaxb.ProvidePersonPermission;
  35. import org.openxdm.xcap.client.appusage.presrules.jaxb.ProvideServicePermission;
  36. import org.openxdm.xcap.client.appusage.presrules.jaxb.UnknownBooleanPermission;
  37. import org.openxdm.xcap.client.appusage.presrules.jaxb.commonpolicy.ActionsType;
  38. import org.openxdm.xcap.client.appusage.presrules.jaxb.commonpolicy.ExceptType;
  39. import org.openxdm.xcap.client.appusage.presrules.jaxb.commonpolicy.IdentityType;
  40. import org.openxdm.xcap.client.appusage.presrules.jaxb.commonpolicy.ManyType;
  41. import org.openxdm.xcap.client.appusage.presrules.jaxb.commonpolicy.OneType;
  42. import org.openxdm.xcap.client.appusage.presrules.jaxb.commonpolicy.RuleType;
  43. import org.openxdm.xcap.client.appusage.presrules.jaxb.commonpolicy.Ruleset;
  44. import org.openxdm.xcap.client.appusage.presrules.jaxb.commonpolicy.SphereType;
  45. import org.openxdm.xcap.client.appusage.presrules.jaxb.commonpolicy.TransformationsType;
  46. import org.openxdm.xcap.client.appusage.presrules.jaxb.commonpolicy.ValidityType;
  47. import org.openxdm.xcap.common.uri.DocumentSelector;
  48. public class RulesetProcessor {
  49. private String subscriber;
  50. private String notifier;
  51. private PublishedSphereSource publishedSphereSource;
  52. private OMAPresRule combinedRule;
  53. private DocumentSelector documentSelector;
  54. public RulesetProcessor(String subscriber, String notifier,
  55. Ruleset ruleset, DocumentSelector documentSelector,
  56. PublishedSphereSource publishedSphereSource) {
  57. this.subscriber = subscriber;
  58. this.notifier = notifier;
  59. this.publishedSphereSource = publishedSphereSource;
  60. this.documentSelector = documentSelector;
  61. processRuleset(ruleset);
  62. }
  63. public String getSubscriber() {
  64. return subscriber;
  65. }
  66. public OMAPresRule getCombinedRule() {
  67. return combinedRule;
  68. }
  69. // ----------------------------- RULE SET PROCESSING ---------------
  70. private void processRuleset(Ruleset ruleset) {
  71. for (RuleType ruleType : ruleset.getRule()) {
  72. // process actions
  73. SubHandlingAction subHandling = processActions(ruleType);
  74. if (subHandling == null) {
  75. // continue, this rule has nothing to do with pres-rules auth
  76. continue;
  77. }
  78. // process conditions
  79. boolean permissionGranted = processConditions(ruleType);
  80. if (permissionGranted) {
  81. // process transformations
  82. OMAPresRule omaPresRule = processTransformations(ruleType);
  83. if (omaPresRule != null) {
  84. // set sub-handling
  85. omaPresRule.setSubHandling(subHandling);
  86. // combine rule
  87. if (combinedRule == null) {
  88. combinedRule = omaPresRule;
  89. } else {
  90. combinedRule.combine(omaPresRule);
  91. }
  92. }
  93. }
  94. }
  95. if (combinedRule == null) {
  96. combinedRule = new OMAPresRule(documentSelector);
  97. }
  98. }
  99. /**
  100. * process rule's actions
  101. *
  102. * @param ruleType
  103. * @return the sub-handling value found
  104. */
  105. private SubHandlingAction processActions(RuleType ruleType) {
  106. ActionsType actionsType = ruleType.getActions();
  107. if (actionsType != null) {
  108. List anys = actionsType.getAny();
  109. if (anys.size() == 1 && anys.get(0) instanceof JAXBElement) {
  110. JAXBElement element = (JAXBElement) anys.get(0);
  111. if (element.getName().getLocalPart().equals("sub-handling")) {
  112. String subHandlingValue = (String) element.getValue();
  113. // 0 is block, 10 is confirm, 20 is polite-block (not
  114. // supported yet), 30 is allow
  115. if (subHandlingValue.equals("allow")
  116. || subHandlingValue.equals("30")) {
  117. return SubHandlingAction.allow;
  118. } else if (subHandlingValue.equals("polite-block")
  119. || subHandlingValue.equals("20")) {
  120. return SubHandlingAction.politeblock;
  121. } else if (subHandlingValue.equals("confirm")
  122. || subHandlingValue.equals("10")) {
  123. return SubHandlingAction.confirm;
  124. } else if (subHandlingValue.equals("block")
  125. || subHandlingValue.equals("0")) {
  126. return SubHandlingAction.block;
  127. }
  128. }
  129. }
  130. }
  131. return null;
  132. }
  133. /**
  134. * process rules's conditions
  135. *
  136. * @param ruleType
  137. * @return true if permission is granted to apply actions and
  138. * transformations of the rule
  139. */
  140. private boolean processConditions(RuleType ruleType) {
  141. String subscriberDomain = null;
  142. // all conditions must evaluate to true
  143. List identityOrSphereOrValidityObjectList = ruleType.getConditions()
  144. .getIdentityOrSphereOrValidity();
  145. if (identityOrSphereOrValidityObjectList.isEmpty()) {
  146. return false;
  147. } else {
  148. for (Object identityOrSphereOrValidityObject : identityOrSphereOrValidityObjectList) {
  149. if (identityOrSphereOrValidityObject instanceof JAXBElement) {
  150. JAXBElement identityOrSphereOrValidity = (JAXBElement) identityOrSphereOrValidityObject;
  151. if (identityOrSphereOrValidity.getValue() instanceof IdentityType) {
  152. IdentityType identityType = (IdentityType) identityOrSphereOrValidity
  153. .getValue();
  154. // identity permission is granted if one sub-clause
  155. // matches subscriber
  156. boolean idPermission = false;
  157. for (Object oneOrManyOrAnyObject : identityType
  158. .getOneOrManyOrAny()) {
  159. JAXBElement oneOrManyOrAny = (JAXBElement) oneOrManyOrAnyObject;
  160. if (oneOrManyOrAny.getValue() instanceof OneType) {
  161. OneType oneType = (OneType) oneOrManyOrAny
  162. .getValue();
  163. if (subscriber.equals(oneType.getId())) {
  164. // found identity of subscriber
  165. idPermission = true;
  166. break;
  167. }
  168. }
  169. else if (oneOrManyOrAny.getValue() instanceof ManyType) {
  170. ManyType manyType = (ManyType) oneOrManyOrAny
  171. .getValue();
  172. if (subscriberDomain == null) {
  173. int i = subscriber.indexOf('@');
  174. if (i > 0) {
  175. subscriberDomain = subscriber
  176. .substring(i + 1);
  177. }
  178. }
  179. if (manyType.getDomain() == null
  180. || domainsMatch(subscriberDomain,
  181. manyType.getDomain())) {
  182. boolean exceptNotFound = true;
  183. for (Object exceptOrAnyObject : manyType
  184. .getExceptOrAny()) {
  185. JAXBElement exceptOrAny = (JAXBElement) exceptOrAnyObject;
  186. if (exceptOrAny.getValue() instanceof ExceptType) {
  187. ExceptType exceptType = (ExceptType) exceptOrAny
  188. .getValue();
  189. if (subscriber.equals(exceptType
  190. .getId())) {
  191. // found subscriber as exception
  192. // in domain
  193. exceptNotFound = false;
  194. break;
  195. } else if (domainsMatch(
  196. subscriberDomain,
  197. exceptType.getDomain())) {
  198. // found subscriber domain as
  199. // exception in domain
  200. exceptNotFound = false;
  201. break;
  202. }
  203. }
  204. }
  205. if (exceptNotFound) {
  206. idPermission = true;
  207. break;
  208. }
  209. }
  210. }
  211. }
  212. if (!idPermission) {
  213. return false;
  214. }
  215. }
  216. else if (identityOrSphereOrValidity.getValue() instanceof SphereType) {
  217. SphereType sphereType = (SphereType) identityOrSphereOrValidity
  218. .getValue();
  219. // we need current sphere published by notifier
  220. String sphere = publishedSphereSource
  221. .getSphere(notifier);
  222. if (sphereType.getValue() == null
  223. || spheresMatch(sphere, sphereType.getValue())) {
  224. return false;
  225. }
  226. }
  227. else if (identityOrSphereOrValidity.getValue() instanceof ValidityType) {
  228. ValidityType validityType = (ValidityType) identityOrSphereOrValidity
  229. .getValue();
  230. /*
  231. * The <validity> element is the third condition element
  232. * specified in this document. It expresses the rule
  233. * validity period by two attributes, a starting and an
  234. * ending time. The validity condition is TRUE if the
  235. * current time is greater than or equal to at least one
  236. * <from> child, but less than the <until> child after
  237. * it. This represents a logical OR operation across
  238. * each <from> and <until> pair. Times are expressed in
  239. * XML dateTime format.
  240. */
  241. if (validityType.getFromAndUntil().size() % 2 == 0) {
  242. // verified we have a pair number of subclauses
  243. }
  244. boolean valid = false;
  245. XMLGregorianCalendar calendar = null;
  246. try {
  247. calendar = DatatypeFactory.newInstance()
  248. .newXMLGregorianCalendar(
  249. new GregorianCalendar());
  250. } catch (DatatypeConfigurationException e) {
  251. System.err
  252. .println("Failed to create calendar to verify pres-rules condition validity");
  253. e.printStackTrace();
  254. }
  255. if (calendar != null) {
  256. for (Iterator<JAXBElement<XMLGregorianCalendar>> iterator = validityType
  257. .getFromAndUntil().iterator(); iterator
  258. .hasNext();) {
  259. JAXBElement<XMLGregorianCalendar> fromElement = iterator
  260. .next();
  261. JAXBElement<XMLGregorianCalendar> untilElement = iterator
  262. .next();
  263. if (fromElement.getName().getLocalPart()
  264. .equals("from")
  265. && untilElement.getName()
  266. .getLocalPart().equals("until")) {
  267. if (fromElement.getValue()
  268. .compare(calendar) < 1
  269. && untilElement.getValue().compare(
  270. calendar) > -1) {
  271. valid = true;
  272. break;
  273. }
  274. } else {
  275. // invalid condition, fail
  276. valid = false;
  277. break;
  278. }
  279. }
  280. }
  281. if (!valid) {
  282. return false;
  283. }
  284. }
  285. }
  286. }
  287. // no conditions evaluated to false;
  288. return true;
  289. }
  290. }
  291. /**
  292. * process rule's transformations
  293. *
  294. * @param ruleType
  295. * @return a {@link OMAPresRule} filled with transformations
  296. */
  297. private OMAPresRule processTransformations(RuleType ruleType) {
  298. return processTransformations(ruleType, documentSelector);
  299. }
  300. public static OMAPresRule processTransformations(RuleType ruleType,
  301. DocumentSelector documentSelector) {
  302. // conditions applies to subscription, let's get rule transformations
  303. TransformationsType transformationsType = ruleType.getTransformations();
  304. if (transformationsType != null) {
  305. // create rule
  306. OMAPresRule rule = new OMAPresRule(documentSelector);
  307. // fill transformations
  308. for (Object transformationObject : transformationsType.getAny()) {
  309. if (transformationObject instanceof ProvideAllAttributes) {
  310. rule.setProvideAllAttributes(true);
  311. }
  312. /*
  313. * else if(transformationObject instanceof
  314. * ProvideDevicePermission) {
  315. * rule.processDevicePermission((ProvideDevicePermission
  316. * )transformationObject); } else if(transformationObject
  317. * instanceof ProvidePersonPermission) {
  318. * rule.processPersonPermission((ProvidePersonPermission)
  319. * transformationObject); } else if(transformationObject
  320. * instanceof ProvideServicePermission) {
  321. * rule.processServicePermission((ProvideServicePermission)
  322. * transformationObject); } else if(transformationObject
  323. * instanceof UnknownBooleanPermission) {
  324. * UnknownBooleanPermission unknownBooleanPermission =
  325. * (UnknownBooleanPermission) transformationObject;
  326. * rule.getUnknownBooleanAttributes().add(new
  327. * UnknownBooleanAttributeTransformation
  328. * (unknownBooleanPermission
  329. * .getName(),unknownBooleanPermission.getNs())); }
  330. */
  331. else if (transformationObject instanceof JAXBElement) {
  332. JAXBElement element = (JAXBElement) transformationObject;
  333. if (element.getName().getNamespaceURI()
  334. .equals("urn:oma:xml:prs:pres-rules")) {
  335. // oma transformations
  336. if (element.getName().getLocalPart()
  337. .equals("provide-registration-state")) {
  338. rule.setProvideRegistrationState(((Boolean) element
  339. .getValue()).booleanValue());
  340. } else if (element.getName().getLocalPart()
  341. .equals("provide-network-availability")) {
  342. rule.setProvideNetworkAvailability(((Boolean) element
  343. .getValue()).booleanValue());
  344. } else if (element.getName().getLocalPart()
  345. .equals("provide-willingness")) {
  346. rule.setProvideWillingness(((Boolean) element
  347. .getValue()).booleanValue());
  348. } else if (element.getName().getLocalPart()
  349. .equals("provide-barring-state")) {
  350. rule.setProvideBarringState(((Boolean) element
  351. .getValue()).booleanValue());
  352. } else if (element.getName().getLocalPart()
  353. .equals("provide-session-participation")) {
  354. rule.setProvideSessionParticipation(((Boolean) element
  355. .getValue()).booleanValue());
  356. } else if (element.getName().getLocalPart()
  357. .equals("service-id")) {
  358. Set<String> s = rule.getServiceIDs();
  359. if (s == null) {
  360. s = new HashSet<String>();
  361. rule.setServiceIDs(s);
  362. }
  363. s.add((String) element.getValue());
  364. } else if (element.getName().getLocalPart()
  365. .equals("provide-geopriv")) {
  366. String value = (String) element.getValue();
  367. if (value != null) {
  368. rule.setProvideGeopriv(GeoPrivTransformation
  369. .valueOf(value.toUpperCase()));
  370. }
  371. }
  372. // unknown transformation, ignore
  373. } else if (element.getName().getNamespaceURI()
  374. .equals("urn:ietf:params:xml:ns:pres-rules")) {
  375. // ietf transformations
  376. if (element.getName().getLocalPart()
  377. .equals("provide-devices")) {
  378. rule.processDevicePermission((ProvideDevicePermission) element
  379. .getValue());
  380. } else if (element.getName().getLocalPart()
  381. .equals("provide-persons")) {
  382. rule.processPersonPermission((ProvidePersonPermission) element
  383. .getValue());
  384. } else if (element.getName().getLocalPart()
  385. .equals("provide-services")) {
  386. rule.processServicePermission((ProvideServicePermission) element
  387. .getValue());
  388. } else if (element.getName().getLocalPart()
  389. .equals("provide-unknown-attribute")) {
  390. UnknownBooleanPermission unknownBooleanPermission = (UnknownBooleanPermission) element
  391. .getValue();
  392. Set<UnknownBooleanAttributeTransformation> s = rule
  393. .getUnknownBooleanAttributes();
  394. if (s == null) {
  395. s = new HashSet<UnknownBooleanAttributeTransformation>();
  396. rule.setUnknownBooleanAttributes(s);
  397. }
  398. s.add(new UnknownBooleanAttributeTransformation(
  399. unknownBooleanPermission.getName(),
  400. unknownBooleanPermission.getNs()));
  401. } else if (element.getName().getLocalPart()
  402. .equals("provide-place-is")) {
  403. rule.setProvidePlaceIs(((Boolean) element
  404. .getValue()).booleanValue());
  405. } else if (element.getName().getLocalPart()
  406. .equals("provide-privacy")) {
  407. rule.setProvidePrivacy(((Boolean) element
  408. .getValue()).booleanValue());
  409. } else if (element.getName().getLocalPart()
  410. .equals("provide-class")) {
  411. rule.setProvideClass(((Boolean) element.getValue())
  412. .booleanValue());
  413. } else if (element.getName().getLocalPart()
  414. .equals("provide-place-type")) {
  415. rule.setProvidePlaceType(((Boolean) element
  416. .getValue()).booleanValue());
  417. } else if (element.getName().getLocalPart()
  418. .equals("provide-relationship")) {
  419. rule.setProvideRelationship(((Boolean) element
  420. .getValue()).booleanValue());
  421. } else if (element.getName().getLocalPart()
  422. .equals("provide-mood")) {
  423. rule.setProvideMood(((Boolean) element.getValue())
  424. .booleanValue());
  425. } else if (element.getName().getLocalPart()
  426. .equals("provide-activities")) {
  427. rule.setProvideActivities(((Boolean) element
  428. .getValue()).booleanValue());
  429. } else if (element.getName().getLocalPart()
  430. .equals("provide-sphere")) {
  431. rule.setProvideSphere(((Boolean) element.getValue())
  432. .booleanValue());
  433. } else if (element.getName().getLocalPart()
  434. .equals("provide-user-input")) {
  435. String value = (String) element.getValue();
  436. if (value != null) {
  437. rule.setProvideUserInput(UserInputTransformation
  438. .valueOf(value.toUpperCase()));
  439. }
  440. } else if (element.getName().getLocalPart()
  441. .equals("provide-time-offset")) {
  442. rule.setProvideTimeOffset(((Boolean) element
  443. .getValue()).booleanValue());
  444. } else if (element.getName().getLocalPart()
  445. .equals("provide-note")) {
  446. rule.setProvideNote(((Boolean) element.getValue())
  447. .booleanValue());
  448. } else if (element.getName().getLocalPart()
  449. .equals("provide-deviceID")) {
  450. rule.setProvideDeviceID(((Boolean) element
  451. .getValue()).booleanValue());
  452. } else if (element.getName().getLocalPart()
  453. .equals("provide-status-icon")) {
  454. rule.setProvideStatusIcon(((Boolean) element
  455. .getValue()).booleanValue());
  456. }
  457. // else unknown transformation, ignore
  458. }
  459. // else unknown transformation, ignore
  460. }
  461. // else unknown transformation, ignore
  462. }
  463. return rule;
  464. } else {
  465. // no transformations
  466. return null;
  467. }
  468. }
  469. private boolean domainsMatch(String domain, String conditionDomain) {
  470. // conditionDomain can be null
  471. // FIXME proper domain matching
  472. /*
  473. * Common policy MUST either use UTF-8 or UTF-16 to store domain names
  474. * in the 'domain' attribute. For non-IDNs (Internationalized Domain
  475. * Names), lowercase ASCII SHOULD be used. For the comparison operation
  476. * between the value stored in the 'domain' attribute and the domain
  477. * value provided via the using protocol (referred to as "protocol
  478. * domain identifier"), the following rules are applicable:
  479. *
  480. * 1. Translate percent-encoding for either string.
  481. *
  482. * 2. Convert both domain strings using the ToASCII operation described
  483. * in RFC 3490 [3].
  484. *
  485. * 3. Compare the two domain strings for ASCII equality, for each label.
  486. * If the string comparison for each label indicates equality, the
  487. * comparison succeeds. Otherwise, the domains are not equal.
  488. *
  489. * If the conversion fails in step (2), the domains are not equal.
  490. */
  491. return domain.equals(conditionDomain);
  492. }
  493. private boolean spheresMatch(String sphere, String conditionSphere) {
  494. // sphere can be null
  495. /*
  496. * The <sphere> element belongs to the group of condition elements. It
  497. * can be used to indicate a state (e.g., 'work', 'home', 'meeting',
  498. * 'travel') the PT is currently in. A sphere condition matches only if
  499. * the PT is currently in the state indicated. The state may be conveyed
  500. * by manual configuration or by some protocol. For example, RPID [10]
  501. * provides the ability to inform the PS of its current sphere. The
  502. * application domain needs to describe in more detail how the sphere
  503. * state is determined. Switching from one sphere to another causes a
  504. * switch between different modes of visibility. As a result, different
  505. * subsets of rules might be applicable.
  506. *
  507. * The content of the 'value' attribute of the <sphere> element MAY
  508. * contain more than one token. The individual tokens MUST be separated
  509. * by a blank character. A logical OR is used for the matching the
  510. * tokens against the sphere settings of the PT. As an example, if the
  511. * content of the 'value' attribute in the sphere attribute contains two
  512. * tokens 'work' and 'home' then this part of the rule matches if the
  513. * sphere for a particular PT is either 'work' OR 'home'. To compare the
  514. * content of the 'value' attribute in the <sphere> element with the
  515. * stored state information about the PT's sphere setting a
  516. * case-insensitive string comparison MUST be used for each individual
  517. * token. There is neither a registry for these values nor a language-
  518. * specific indication of the sphere content. As such, the tokens are
  519. * treated as opaque strings.
  520. */
  521. String[] conditionSphereTokens = conditionSphere.split(" ");
  522. for (String conditionSphereToken : conditionSphereTokens) {
  523. if (conditionSphereToken.equalsIgnoreCase(sphere)) {
  524. return true;
  525. }
  526. }
  527. return false;
  528. }
  529. }