PageRenderTime 30ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

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

http://mobicents.googlecode.com/
Java | 419 lines | 317 code | 37 blank | 65 comment | 62 complexity | 84e5c3a44fe97130a209ba5b990b34b6 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;
  23. import java.util.HashMap;
  24. import java.util.Map.Entry;
  25. import javax.sip.ServerTransaction;
  26. import javax.sip.message.Response;
  27. import javax.slee.ActivityContextInterface;
  28. import javax.slee.resource.StartActivityException;
  29. import org.apache.log4j.Logger;
  30. import org.mobicents.slee.sipevent.server.publication.data.ComposedPublication;
  31. import org.mobicents.slee.sipevent.server.subscription.NotifyContent;
  32. import org.mobicents.slee.sipevent.server.subscription.data.Notifier;
  33. import org.mobicents.slee.sipevent.server.subscription.data.Subscription;
  34. import org.mobicents.slee.sipevent.server.subscription.data.SubscriptionKey;
  35. import org.mobicents.slee.sippresence.server.presrulescache.PresRulesActivity;
  36. import org.mobicents.slee.sippresence.server.subscription.rules.OMAPresRule;
  37. import org.mobicents.slee.sippresence.server.subscription.rules.OMAPresRuleDOMTransformer;
  38. import org.mobicents.slee.sippresence.server.subscription.rules.PresRuleCMPKey;
  39. import org.mobicents.slee.sippresence.server.subscription.rules.RulesetProcessor;
  40. import org.mobicents.slee.sippresence.server.subscription.rules.SubHandlingAction;
  41. import org.mobicents.xdm.common.util.dom.DomUtils;
  42. import org.openxdm.xcap.client.appusage.presrules.jaxb.commonpolicy.Ruleset;
  43. import org.openxdm.xcap.common.uri.DocumentSelector;
  44. import org.w3c.dom.Document;
  45. import org.w3c.dom.Element;
  46. import org.w3c.dom.Node;
  47. import org.w3c.dom.NodeList;
  48. /**
  49. * Logic for the sip presence subscription control, which complements the SIP
  50. * Event generic logic.
  51. *
  52. * @author martins
  53. *
  54. */
  55. public class PresenceSubscriptionControl {
  56. private static Logger logger = Logger
  57. .getLogger(PresenceSubscriptionControl.class);
  58. private static final OMAPresRuleDOMTransformer PRES_RULE_TRANSFORMER = new OMAPresRuleDOMTransformer();
  59. private static final String[] eventPackages = { "presence" };
  60. public static String[] getEventPackages() {
  61. return eventPackages;
  62. }
  63. @SuppressWarnings("unchecked")
  64. public void isSubscriberAuthorized(String subscriber,
  65. String subscriberDisplayName, Notifier notifier,
  66. SubscriptionKey key, int expires, String content,
  67. String contentType, String contentSubtype, boolean eventList,
  68. String presRulesAUID, String presRulesDocumentName,
  69. ServerTransaction serverTransaction,
  70. PresenceSubscriptionControlSbbInterface sbb) {
  71. DocumentSelector documentSelector = getDocumentSelector(
  72. notifier.getUri(), presRulesAUID, presRulesDocumentName);
  73. if (documentSelector == null) {
  74. if (logger.isDebugEnabled()) {
  75. logger.debug("Failed to create document selector for notifier "
  76. + notifier.getUri()
  77. + ", can't proceed with subscription.");
  78. }
  79. sbb.getParentSbb().newSubscriptionAuthorization(subscriber,
  80. subscriberDisplayName, notifier, key, expires,
  81. Response.FORBIDDEN, eventList, serverTransaction);
  82. return;
  83. }
  84. // get pres rules activity and attach sbb to receive updates
  85. PresRulesActivity activity = null;
  86. try {
  87. activity = sbb.getPresRulesSbbInterface().getActivity(
  88. documentSelector);
  89. } catch (StartActivityException e) {
  90. logger.error(
  91. "Failed to start activity, can't proceed, refusing subscription",
  92. e);
  93. sbb.getParentSbb().newSubscriptionAuthorization(subscriber,
  94. subscriberDisplayName, notifier, key, expires,
  95. Response.FORBIDDEN, eventList, serverTransaction);
  96. return;
  97. }
  98. sbb.getPresRulesACIF().getActivityContextInterface(activity)
  99. .attach(sbb.getSbbLocalObject());
  100. // get ruleset
  101. Ruleset ruleset = activity.getRuleset();
  102. if (ruleset == null) {
  103. if (logger.isInfoEnabled()) {
  104. logger.info("Notifier " + notifier.getUri()
  105. + " has no ruleset, allowing subscription " + key);
  106. }
  107. OMAPresRule combinedRule = new OMAPresRule(documentSelector);
  108. combinedRule.setProvideAllDevices(true);
  109. combinedRule.setProvideAllAttributes(true);
  110. combinedRule.setProvideAllPersons(true);
  111. combinedRule.setProvideAllServices(true);
  112. combinedRule.setSubHandling(SubHandlingAction.allow);
  113. HashMap<PresRuleCMPKey, OMAPresRule> combinedRules = sbb
  114. .getCombinedRules();
  115. if (combinedRules == null) {
  116. combinedRules = new HashMap<PresRuleCMPKey, OMAPresRule>();
  117. }
  118. combinedRules.put(new PresRuleCMPKey(subscriber, notifier, key),
  119. combinedRule);
  120. sbb.setCombinedRules(combinedRules);
  121. sbb.getParentSbb().newSubscriptionAuthorization(subscriber,
  122. subscriberDisplayName, notifier, key, expires, Response.OK,
  123. eventList, serverTransaction);
  124. return;
  125. }
  126. // process ruleset
  127. RulesetProcessor rulesetProcessor = new RulesetProcessor(subscriber,
  128. notifier.getUri(), ruleset, documentSelector, sbb);
  129. OMAPresRule combinedRule = rulesetProcessor.getCombinedRule();
  130. int responseCode = combinedRule.getSubHandling().getResponseCode();
  131. if (responseCode < 300) {
  132. // save combined rule, the subscription will be created
  133. HashMap<PresRuleCMPKey, OMAPresRule> combinedRules = sbb
  134. .getCombinedRules();
  135. if (combinedRules == null) {
  136. combinedRules = new HashMap<PresRuleCMPKey, OMAPresRule>();
  137. }
  138. combinedRules.put(new PresRuleCMPKey(subscriber, notifier, key),
  139. combinedRule);
  140. sbb.setCombinedRules(combinedRules);
  141. }
  142. sbb.getParentSbb().newSubscriptionAuthorization(subscriber,
  143. subscriberDisplayName, notifier, key, expires, responseCode,
  144. eventList, serverTransaction);
  145. }
  146. @SuppressWarnings("unchecked")
  147. public void removingSubscription(Subscription subscription,
  148. String presRulesAUID, String presRulesDocumentName,
  149. PresenceSubscriptionControlSbbInterface sbb) {
  150. if (logger.isDebugEnabled()) {
  151. logger.debug("removingSubscription(" + subscription + ")");
  152. }
  153. // get combined rules cmp
  154. HashMap<PresRuleCMPKey, OMAPresRule> combinedRules = sbb
  155. .getCombinedRules();
  156. if (combinedRules != null) {
  157. // remove subscription from map
  158. if (logger.isDebugEnabled()) {
  159. logger.debug("combined rules: " + combinedRules.keySet());
  160. }
  161. OMAPresRule ruleRemoved = combinedRules.remove(new PresRuleCMPKey(
  162. subscription.getSubscriber(), subscription.getNotifier(),
  163. subscription.getKey()));
  164. if (ruleRemoved != null) {
  165. boolean detachFromPresRulesActivity = true;
  166. for (OMAPresRule rule : combinedRules.values()) {
  167. if (rule.getDocumentSelector().equals(
  168. ruleRemoved.getDocumentSelector())) {
  169. // there is at least another subscription using same
  170. // pres rules activity, can't unsubscribe
  171. detachFromPresRulesActivity = false;
  172. break;
  173. }
  174. }
  175. if (detachFromPresRulesActivity) {
  176. PresRulesActivity activity = null;
  177. try {
  178. activity = sbb.getPresRulesSbbInterface().getActivity(
  179. ruleRemoved.getDocumentSelector());
  180. } catch (StartActivityException e) {
  181. logger.error(e.getMessage(), e);
  182. // ignore
  183. return;
  184. }
  185. ActivityContextInterface aci = sbb.getPresRulesACIF()
  186. .getActivityContextInterface(activity);
  187. aci.detach(sbb.getSbbLocalObject());
  188. }
  189. }
  190. }
  191. }
  192. @SuppressWarnings("unchecked")
  193. public void rulesetUpdated(DocumentSelector documentSelector,
  194. Ruleset ruleset, PresenceSubscriptionControlSbbInterface sbb) {
  195. // get current combined rules from cmp
  196. HashMap<PresRuleCMPKey, OMAPresRule> combinedRules = sbb
  197. .getCombinedRules();
  198. if (combinedRules == null) {
  199. combinedRules = new HashMap<PresRuleCMPKey, OMAPresRule>();
  200. }
  201. // for each combined rules that has the user that updated the doc as
  202. // notifier reprocess the rules
  203. OMAPresRule oldCombinedRule = null;
  204. OMAPresRule newCombinedRule = null;
  205. PresRuleCMPKey presRuleCMPKey = null;
  206. SubscriptionKey subscriptionKey = null;
  207. for (Entry<PresRuleCMPKey, OMAPresRule> entry : combinedRules
  208. .entrySet()) {
  209. oldCombinedRule = entry.getValue();
  210. if (documentSelector.equals(oldCombinedRule.getDocumentSelector())) {
  211. presRuleCMPKey = entry.getKey();
  212. subscriptionKey = presRuleCMPKey.getSubscriptionKey();
  213. newCombinedRule = new RulesetProcessor(
  214. presRuleCMPKey.getSubscriber(), presRuleCMPKey
  215. .getNotifier().getUri(), ruleset,
  216. documentSelector, sbb).getCombinedRule();
  217. combinedRules.put(entry.getKey(), newCombinedRule);
  218. // check permission changed
  219. if (oldCombinedRule.getSubHandling().getResponseCode() != newCombinedRule
  220. .getSubHandling().getResponseCode()) {
  221. sbb.getParentSbb().authorizationChanged(
  222. presRuleCMPKey.getSubscriber(),
  223. presRuleCMPKey.getNotifier(),
  224. subscriptionKey.getEventPackage(),
  225. subscriptionKey.getEventId(),
  226. newCombinedRule.getSubHandling().getResponseCode());
  227. }
  228. // TODO check if transformations changed need any further action
  229. }
  230. }
  231. }
  232. /**
  233. * interface used by rules processor to get sphere for a notifier
  234. */
  235. public String getSphere(String notifier,
  236. PresenceSubscriptionControlSbbInterface sbb) {
  237. // get ridden of notifier uri params, if any
  238. String notifierWithoutParams = notifier.split(";")[0];
  239. ComposedPublication composedPublication = sbb.getPublicationChildSbb()
  240. .getComposedPublication(notifierWithoutParams, "presence");
  241. if (composedPublication == null
  242. || composedPublication.getDocumentAsDOM() == null) {
  243. return null;
  244. }
  245. String sphere = null;
  246. Element presence = composedPublication.getDocumentAsDOM()
  247. .getDocumentElement();
  248. NodeList presenceChilds = presence.getChildNodes();
  249. Node presenceChild = null;
  250. for (int i = 0; i < presenceChilds.getLength(); i++) {
  251. presenceChild = presenceChilds.item(i);
  252. if (DomUtils.isElementNamed(presenceChild, "person")) {
  253. // presence/person element
  254. NodeList personChilds = presenceChild.getChildNodes();
  255. Node personChild = null;
  256. for (int j = 0; j < personChilds.getLength(); j++) {
  257. personChild = personChilds.item(j);
  258. if (DomUtils.isElementNamed(personChild, "sphere")) {
  259. // presence/person/sphere element
  260. String tmpSphere = null;
  261. NodeList sphereChilds = personChild.getChildNodes();
  262. Node sphereChild = null;
  263. for (int l = 0; l < sphereChilds.getLength(); l++) {
  264. sphereChild = sphereChilds.item(l);
  265. if (sphereChild.getNodeType() == Node.ELEMENT_NODE) {
  266. if (tmpSphere == null) {
  267. tmpSphere = DomUtils
  268. .getElementName(sphereChild);
  269. } else {
  270. tmpSphere += " "
  271. + DomUtils
  272. .getElementName(sphereChild);
  273. }
  274. }
  275. }
  276. if (sphere == null) {
  277. sphere = tmpSphere;
  278. } else {
  279. if (!sphere.equals(tmpSphere)) {
  280. // inconsistent sphere values
  281. return null;
  282. }
  283. }
  284. }
  285. }
  286. }
  287. }
  288. return sphere;
  289. }
  290. public NotifyContent getNotifyContent(Subscription subscription,
  291. PresenceSubscriptionControlSbbInterface sbb) {
  292. try {
  293. ComposedPublication composedPublication = sbb
  294. .getPublicationChildSbb().getComposedPublication(
  295. subscription.getNotifier().getUri(),
  296. subscription.getKey().getEventPackage());
  297. if (composedPublication != null
  298. && composedPublication.getDocumentAsDOM() != null) {
  299. Object filteredContent = filterContentPerSubscriber(
  300. subscription, composedPublication.getDocumentAsDOM(),
  301. false, sbb);
  302. if (filteredContent != null) {
  303. return new NotifyContent(filteredContent, sbb
  304. .getHeaderFactory().createContentTypeHeader(
  305. composedPublication.getContentType(),
  306. composedPublication.getContentSubType()),
  307. null);
  308. }
  309. }
  310. } catch (Exception e) {
  311. logger.error("failed to get notify content", e);
  312. }
  313. return null;
  314. }
  315. public Object filterContentPerSubscriber(Subscription subscription,
  316. Object unmarshalledContent,
  317. PresenceSubscriptionControlSbbInterface sbb) {
  318. return filterContentPerSubscriber(subscription, unmarshalledContent, true, sbb);
  319. }
  320. @SuppressWarnings("unchecked")
  321. private Object filterContentPerSubscriber(Subscription subscription,
  322. Object unmarshalledContent, boolean stateChange,
  323. PresenceSubscriptionControlSbbInterface sbb) {
  324. if (unmarshalledContent == null) {
  325. return null;
  326. }
  327. if (!(unmarshalledContent instanceof Document)) {
  328. logger.warn("request to filter notify content with an unexpected content of type: "
  329. + unmarshalledContent.getClass());
  330. return unmarshalledContent;
  331. }
  332. // get rules for subscriptions on this sbb entity (sip dialog)
  333. HashMap<PresRuleCMPKey, OMAPresRule> combinedRules = sbb
  334. .getCombinedRules();
  335. if (combinedRules == null) {
  336. // no rules, return full content
  337. return unmarshalledContent;
  338. }
  339. // get rule for this specific subscription
  340. final OMAPresRule rule = combinedRules.get(new PresRuleCMPKey(
  341. subscription.getSubscriber(), subscription.getNotifier(),
  342. subscription.getKey()));
  343. if (rule == null) {
  344. // no rule for the subscription, return full content
  345. return unmarshalledContent;
  346. }
  347. if (rule.getSubHandling() == SubHandlingAction.allow) {
  348. // apply transformations
  349. try {
  350. return PRES_RULE_TRANSFORMER.transform(
  351. (Document) unmarshalledContent, rule);
  352. } catch (Exception e) {
  353. logger.error("failed to apply rule in content filtering for "
  354. + subscription, e);
  355. return null;
  356. }
  357. } else {
  358. if (rule.getSubHandling() != SubHandlingAction.politeblock) {
  359. logger.warn("request to filter notify content with an unexpected sub-handling value: "
  360. + rule.getSubHandling());
  361. }
  362. // TODO consider to create polite block notify content instead of no
  363. // content, as OMA specs say, for no state change notifications
  364. // emmartins: to me polite blocking is accepting subscription but
  365. // never show any state, thus no notify content
  366. return null;
  367. }
  368. }
  369. // --------- AUX
  370. /**
  371. * from a user return the document selector pointing to it's pres-rules
  372. *
  373. * @param user
  374. * @return
  375. */
  376. private DocumentSelector getDocumentSelector(String user,
  377. String presRulesAUID, String presRulesDocumentName) {
  378. return new DocumentSelector(new StringBuilder(presRulesAUID)
  379. .append("/users/").append(user).toString(),
  380. presRulesDocumentName);
  381. }
  382. }