PageRenderTime 28ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/servers/sip-presence/xdm/server/core/subscription-control/sbb/src/main/java/org/mobicents/slee/xdm/server/subscription/XcapDiffSubscriptionControl.java

http://mobicents.googlecode.com/
Java | 796 lines | 657 code | 48 blank | 91 comment | 132 complexity | 3a2f3eb551ed4af97cf5339818f0ab08 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.xdm.server.subscription;
  23. import java.io.StringReader;
  24. import java.text.ParseException;
  25. import java.util.Collections;
  26. import java.util.HashMap;
  27. import java.util.HashSet;
  28. import java.util.Map;
  29. import java.util.Set;
  30. import javax.sip.ServerTransaction;
  31. import javax.sip.header.ContentTypeHeader;
  32. import javax.sip.header.EventHeader;
  33. import javax.sip.message.Response;
  34. import javax.slee.ActivityContextInterface;
  35. import javax.slee.SbbLocalObject;
  36. import javax.xml.transform.TransformerException;
  37. import javax.xml.xpath.XPath;
  38. import javax.xml.xpath.XPathConstants;
  39. import javax.xml.xpath.XPathExpressionException;
  40. import org.apache.log4j.Logger;
  41. import org.mobicents.protocols.xcap.diff.BuildPatchException;
  42. import org.mobicents.protocols.xcap.diff.dom.DOMXcapDiffFactory;
  43. import org.mobicents.protocols.xcap.diff.dom.DOMXcapDiffPatchBuilder;
  44. import org.mobicents.slee.sipevent.server.subscription.NotifyContent;
  45. import org.mobicents.slee.sipevent.server.subscription.data.Notifier;
  46. import org.mobicents.slee.sipevent.server.subscription.data.Subscription;
  47. import org.mobicents.slee.sipevent.server.subscription.data.SubscriptionKey;
  48. import org.mobicents.slee.xdm.server.ServerConfiguration;
  49. import org.mobicents.xdm.common.util.dom.DomUtils;
  50. import org.mobicents.xdm.server.appusage.AppUsage;
  51. import org.mobicents.xdm.server.appusage.AppUsageManagement;
  52. import org.openxdm.xcap.common.datasource.Document;
  53. import org.openxdm.xcap.common.error.InternalServerErrorException;
  54. import org.openxdm.xcap.common.uri.DocumentSelector;
  55. import org.openxdm.xcap.common.uri.NodeSelector;
  56. import org.openxdm.xcap.common.uri.Parser;
  57. import org.openxdm.xcap.common.uri.ResourceSelector;
  58. import org.openxdm.xcap.common.xml.TextWriter;
  59. import org.openxdm.xcap.server.slee.resource.datasource.CollectionActivity;
  60. import org.openxdm.xcap.server.slee.resource.datasource.DataSourceActivityContextInterfaceFactory;
  61. import org.openxdm.xcap.server.slee.resource.datasource.DataSourceSbbInterface;
  62. import org.openxdm.xcap.server.slee.resource.datasource.DocumentActivity;
  63. import org.openxdm.xcap.server.slee.resource.datasource.DocumentUpdatedEvent;
  64. import org.openxdm.xcap.server.slee.resource.datasource.NodeSubscription;
  65. import org.w3c.dom.Attr;
  66. import org.w3c.dom.Element;
  67. import org.w3c.dom.Node;
  68. import org.w3c.dom.NodeList;
  69. import org.xml.sax.InputSource;
  70. /**
  71. * Logic for {@link XcapDiffSubscriptionControlSbb}
  72. *
  73. * @author martins
  74. *
  75. */
  76. public class XcapDiffSubscriptionControl {
  77. private static final String[] xcapDiffEventPackages = { "xcap-diff" };
  78. private static final AppUsageManagement APP_USAGE_MANAGEMENT = AppUsageManagement
  79. .getInstance();
  80. private static final ServerConfiguration XDM_SERVER_CONFIGURATION = ServerConfiguration
  81. .getInstance();
  82. private final Map<String, String> EVENT_HEADER_PATCHING_PARAMS = initEventHeaderPatchingParams();
  83. private Map<String, String> initEventHeaderPatchingParams() {
  84. Map<String, String> map = new HashMap<String, String>();
  85. map.put(DiffProcessing.PARAM, DiffProcessing.XcapPatching.toString());
  86. return Collections.unmodifiableMap(map);
  87. }
  88. public static String[] getEventPackages() {
  89. return xcapDiffEventPackages;
  90. }
  91. private ContentTypeHeader xcapDiffContentTypeHeader = null;
  92. public ContentTypeHeader getXcapDiffContentTypeHeader(
  93. XcapDiffSubscriptionControlSbbInterface sbb) {
  94. if (xcapDiffContentTypeHeader == null) {
  95. try {
  96. xcapDiffContentTypeHeader = sbb
  97. .getHeaderFactory()
  98. .createContentTypeHeader("application", "xcap-diff+xml");
  99. } catch (ParseException e) {
  100. // ignore
  101. e.printStackTrace();
  102. }
  103. }
  104. return xcapDiffContentTypeHeader;
  105. }
  106. public void isSubscriberAuthorized(String subscriber,
  107. String subscriberDisplayName, Notifier notifier,
  108. SubscriptionKey key, int expires, String content,
  109. String contentType, String contentSubtype, boolean eventList,
  110. ServerTransaction serverTransaction,
  111. XcapDiffSubscriptionControlSbbInterface sbb) {
  112. DiffProcessing diffProcessing = DiffProcessing.NoPatching;
  113. if (serverTransaction != null) {
  114. // sip subscription
  115. EventHeader eventHeader = (EventHeader) serverTransaction
  116. .getRequest().getHeader(EventHeader.NAME);
  117. if (eventHeader != null) {
  118. diffProcessing = DiffProcessing.fromString(eventHeader
  119. .getParameter(DiffProcessing.PARAM));
  120. }
  121. }
  122. if (content == null) {
  123. if (logger.isDebugEnabled()) {
  124. logger.debug("xcap diff subscription request includes no content, replying forbidden");
  125. }
  126. sbb.getParentSbb().newSubscriptionAuthorization(subscriber,
  127. subscriberDisplayName, notifier, key, expires,
  128. Response.FORBIDDEN, eventList, serverTransaction);
  129. return;
  130. }
  131. try {
  132. org.w3c.dom.Document document = DomUtils.DOCUMENT_BUILDER_NS_AWARE_FACTORY
  133. .newDocumentBuilder().parse(
  134. new InputSource(new StringReader(content)));
  135. Element resourceLists = document.getDocumentElement();
  136. // ok, resource-lists parsed, let's process it's lists elements
  137. HashSet<String> collectionsToSubscribe = null;
  138. HashSet<DocumentSelector> documentsToSubscribe = new HashSet<DocumentSelector>();
  139. HashSet<NodeSubscription> nodeSubscriptions = new HashSet<NodeSubscription>();
  140. NodeList resourceListsChilds = resourceLists.getChildNodes();
  141. for (int i = 0; i < resourceListsChilds.getLength(); i++) {
  142. Node resourceListsChild = resourceListsChilds.item(i);
  143. if (DomUtils.isElementNamed(resourceListsChild, "list")) {
  144. // resource-lists/list
  145. NodeList listChilds = resourceListsChild.getChildNodes();
  146. Node listChild = null;
  147. String uri = null;
  148. for (int j = 0; j < listChilds.getLength(); j++) {
  149. listChild = listChilds.item(j);
  150. if (DomUtils.isElementNamed(listChild, "entry")) {
  151. // resource-lists/list/entry
  152. uri = ((Element) listChild).getAttribute("uri");
  153. // process it
  154. ResourceSelector resourceSelector = null;
  155. try {
  156. int queryComponentSeparator = uri.indexOf('?');
  157. // note: in xcap uris the root start with /, in
  158. // xcap diff it doesn't, due to separation of
  159. // full xcap root from doc collection, so we
  160. // must remove the leading / from config
  161. if (queryComponentSeparator > 0) {
  162. resourceSelector = Parser
  163. .parseResourceSelector(
  164. ServerConfiguration
  165. .getInstance()
  166. .getXcapRoot()
  167. .substring(1),
  168. uri.substring(0,
  169. queryComponentSeparator),
  170. uri.substring(queryComponentSeparator + 1));
  171. } else {
  172. resourceSelector = Parser
  173. .parseResourceSelector(
  174. ServerConfiguration
  175. .getInstance()
  176. .getXcapRoot()
  177. .substring(1), uri,
  178. null);
  179. }
  180. // authorize
  181. if (subscriber != null
  182. && !XDM_SERVER_CONFIGURATION
  183. .getXcapDiffSuperUsers()
  184. .contains(subscriber)) {
  185. // not a super user, may only subscribe its
  186. // own collections
  187. String[] docSelectorParts = resourceSelector
  188. .getDocumentSelector().split("/");
  189. if (docSelectorParts.length < 3
  190. && !docSelectorParts[1]
  191. .equals("users")
  192. && !docSelectorParts[2]
  193. .equals(subscriber)) {
  194. sbb.getParentSbb()
  195. .newSubscriptionAuthorization(
  196. subscriber,
  197. subscriberDisplayName,
  198. notifier, key, expires,
  199. Response.FORBIDDEN,
  200. eventList,
  201. serverTransaction);
  202. return;
  203. }
  204. }
  205. int docSelectorLength = resourceSelector
  206. .getDocumentSelector().length();
  207. if (resourceSelector.getDocumentSelector()
  208. .charAt(docSelectorLength - 1) == '/') {
  209. // trying to subscribe collection
  210. String collection = resourceSelector
  211. .getDocumentSelector().substring(0,
  212. docSelectorLength - 1);
  213. if (logger.isInfoEnabled()) {
  214. logger.info("subscribing collection "
  215. + collection);
  216. }
  217. if (collectionsToSubscribe == null) {
  218. collectionsToSubscribe = new HashSet<String>();
  219. }
  220. collectionsToSubscribe.add(collection);
  221. } else {
  222. // trying to subscribe a document or part of
  223. // it
  224. final DocumentSelector documentSelector = DocumentSelector
  225. .valueOf(resourceSelector
  226. .getDocumentSelector());
  227. // parse node selector if exists
  228. NodeSelector nodeSelector = null;
  229. if (resourceSelector.getNodeSelector() != null) {
  230. nodeSelector = Parser
  231. .parseNodeSelector(
  232. resourceSelector
  233. .getNodeSelector(),
  234. resourceSelector
  235. .getNamespaceContext());
  236. if (nodeSelector.getTerminalSelector() != null) {
  237. // parse terminal selector to
  238. // validate
  239. Parser.parseTerminalSelector(nodeSelector
  240. .getTerminalSelector());
  241. }
  242. NodeSubscription nodeSubscription = new NodeSubscription()
  243. .setDocumentSelector(
  244. documentSelector)
  245. .setNodeSelector(nodeSelector)
  246. .setSel(uri);
  247. if (logger.isInfoEnabled()) {
  248. logger.info("subscribing node "
  249. + nodeSelector
  250. + "of document "
  251. + documentSelector);
  252. }
  253. if (nodeSubscriptions == null) {
  254. nodeSubscriptions = new HashSet<NodeSubscription>();
  255. }
  256. nodeSubscriptions.add(nodeSubscription);
  257. } else {
  258. if (logger.isInfoEnabled()) {
  259. logger.info("subscribing document "
  260. + documentSelector);
  261. }
  262. if (documentsToSubscribe == null) {
  263. documentsToSubscribe = new HashSet<DocumentSelector>();
  264. }
  265. documentsToSubscribe
  266. .add(documentSelector);
  267. }
  268. }
  269. } catch (Exception e) {
  270. logger.error(
  271. "failed to parse entry uri to subscribe, ignoring "
  272. + uri, e);
  273. }
  274. }
  275. }
  276. }
  277. }
  278. // create subscriptions object
  279. Subscriptions subscriptions = new Subscriptions(key, subscriber,
  280. collectionsToSubscribe, documentsToSubscribe,
  281. nodeSubscriptions, diffProcessing);
  282. // get subscriptions map cmp
  283. SubscriptionsMap subscriptionsMap = sbb.getSubscriptionsMap();
  284. if (subscriptionsMap == null) {
  285. subscriptionsMap = new SubscriptionsMap();
  286. }
  287. // build set of other documents and collections already subscribed
  288. // by
  289. // this entity
  290. HashSet<DocumentSelector> documentSelectorsAlreadySubscribed = null;
  291. HashSet<String> collectionsAlreadySubscribed = null;
  292. for (Subscriptions s : subscriptionsMap.getSubscriptions()) {
  293. if (!s.getCollectionSubscriptions().isEmpty()) {
  294. if (collectionsAlreadySubscribed == null) {
  295. collectionsAlreadySubscribed = new HashSet<String>();
  296. }
  297. collectionsAlreadySubscribed.addAll(s
  298. .getCollectionSubscriptions());
  299. }
  300. Set<DocumentSelector> subscribedDocuments = s
  301. .getAllDocumentsToSubscribe();
  302. if (!subscribedDocuments.isEmpty()) {
  303. if (documentSelectorsAlreadySubscribed == null) {
  304. documentSelectorsAlreadySubscribed = new HashSet<DocumentSelector>();
  305. }
  306. documentSelectorsAlreadySubscribed
  307. .addAll(subscribedDocuments);
  308. }
  309. }
  310. // save subscriptions object on cmp
  311. subscriptionsMap.put(subscriptions);
  312. sbb.setSubscriptionsMap(subscriptionsMap);
  313. // let's subscribe all documents and/or collections
  314. DataSourceActivityContextInterfaceFactory dataSourceActivityContextInterfaceFactory = sbb
  315. .getDataSourceActivityContextInterfaceFactory();
  316. DataSourceSbbInterface dataSourceSbbInterface = sbb
  317. .getDataSourceSbbInterface();
  318. SbbLocalObject sbbLocalObject = sbb.getSbbContext()
  319. .getSbbLocalObject();
  320. for (DocumentSelector documentSelector : subscriptions
  321. .getAllDocumentsToSubscribe()) {
  322. if (documentSelectorsAlreadySubscribed == null
  323. || !documentSelectorsAlreadySubscribed
  324. .contains(documentSelector)) {
  325. // this document selector is not subscribed already due
  326. // to another
  327. // subscription in the same entity, so subscribe the doc
  328. DocumentActivity activity = dataSourceSbbInterface
  329. .createDocumentActivity(documentSelector);
  330. ActivityContextInterface aci = dataSourceActivityContextInterfaceFactory
  331. .getActivityContextInterface(activity);
  332. aci.attach(sbbLocalObject);
  333. }
  334. }
  335. for (String collection : subscriptions.getCollectionSubscriptions()) {
  336. if (collectionsAlreadySubscribed == null
  337. || !collectionsAlreadySubscribed.contains(collection)) {
  338. // collections already subscribed does not match this
  339. // collection,
  340. // so subscribe it
  341. CollectionActivity activity = dataSourceSbbInterface
  342. .createCollectionActivity(collection);
  343. ActivityContextInterface aci = dataSourceActivityContextInterfaceFactory
  344. .getActivityContextInterface(activity);
  345. aci.attach(sbbLocalObject);
  346. }
  347. }
  348. // continue new subscription process
  349. sbb.getParentSbb().newSubscriptionAuthorization(subscriber,
  350. subscriberDisplayName, notifier, key, expires, Response.OK,
  351. eventList, serverTransaction);
  352. } catch (Exception e) {
  353. logger.error("failed to parse resource-lists in initial subscribe",
  354. e);
  355. sbb.getParentSbb().newSubscriptionAuthorization(subscriber,
  356. subscriberDisplayName, notifier, key, expires,
  357. Response.FORBIDDEN, eventList, serverTransaction);
  358. }
  359. }
  360. public void removingSubscription(Subscription subscription,
  361. XcapDiffSubscriptionControlSbbInterface sbb) {
  362. // get subscriptions map and remove subscription terminating
  363. SubscriptionsMap subscriptionsMap = sbb.getSubscriptionsMap();
  364. if (subscriptionsMap != null) {
  365. Subscriptions subscriptions = subscriptionsMap.remove(subscription
  366. .getKey());
  367. // build set of other documents and collections already subscribed
  368. // by
  369. // this entity
  370. HashSet<DocumentSelector> documentSelectorsSubscribedByOthers = null;
  371. HashSet<String> collectionsSubscribedByOthers = null;
  372. for (Subscriptions s : subscriptionsMap.getSubscriptions()) {
  373. for (DocumentSelector ds : s.getAllDocumentsToSubscribe()) {
  374. if (documentSelectorsSubscribedByOthers == null) {
  375. documentSelectorsSubscribedByOthers = new HashSet<DocumentSelector>();
  376. }
  377. documentSelectorsSubscribedByOthers.add(ds);
  378. }
  379. for (String collection : s.getCollectionSubscriptions()) {
  380. if (collectionsSubscribedByOthers == null) {
  381. collectionsSubscribedByOthers = new HashSet<String>();
  382. }
  383. collectionsSubscribedByOthers.add(collection);
  384. }
  385. }
  386. // now unsubscribe each that was subscribed only by the subscription
  387. // terminating
  388. SbbLocalObject sbbLocalObject = sbb.getSbbContext()
  389. .getSbbLocalObject();
  390. for (ActivityContextInterface aci : sbb.getSbbContext()
  391. .getActivities()) {
  392. Object activity = aci.getActivity();
  393. if (activity instanceof DocumentActivity) {
  394. String aciDS = ((DocumentActivity) activity)
  395. .getDocumentSelector();
  396. for (DocumentSelector ds : subscriptions
  397. .getDocumentSubscriptions()) {
  398. if (documentSelectorsSubscribedByOthers == null
  399. || (ds.toString().equals(aciDS) && !documentSelectorsSubscribedByOthers
  400. .contains(ds))) {
  401. // safe to unsubscribe this document
  402. aci.detach(sbbLocalObject);
  403. }
  404. }
  405. } else if (activity instanceof CollectionActivity) {
  406. String aciCollection = ((CollectionActivity) activity)
  407. .getCollection();
  408. for (String collection : subscriptions
  409. .getCollectionSubscriptions()) {
  410. if (collectionsSubscribedByOthers == null
  411. || (collection.equals(aciCollection) && !collectionsSubscribedByOthers
  412. .contains(collection))) {
  413. // safe to unsubscribe this collection
  414. aci.detach(sbbLocalObject);
  415. }
  416. }
  417. }
  418. }
  419. } else {
  420. logger.warn("Removing subscription but map of subscriptions is null");
  421. }
  422. }
  423. private static final DOMXcapDiffPatchBuilder XCAP_DIFF_PATCH_BUILDER = new DOMXcapDiffFactory()
  424. .getPatchBuilder();
  425. public NotifyContent getNotifyContent(Subscription subscription,
  426. XcapDiffSubscriptionControlSbbInterface sbb) {
  427. // let's gather all content for this subscription
  428. SubscriptionsMap subscriptionsMap = sbb.getSubscriptionsMap();
  429. if (subscriptionsMap == null) {
  430. logger.error("failed to get notify content for subscription "
  431. + subscription
  432. + ", there are no xcap diff subscriptions map");
  433. return null;
  434. }
  435. Subscriptions subscriptions = subscriptionsMap.get(subscription
  436. .getKey());
  437. if (subscriptions == null) {
  438. logger.error("failed to get notify content for subscription "
  439. + subscription
  440. + ", there are no xcap diff subscriptions for such subscription in map");
  441. return null;
  442. }
  443. Set<Element> patchComponents = new HashSet<Element>();
  444. // let's process first collections
  445. for (String collection : subscriptions.getCollectionSubscriptions()) {
  446. // get documents that exist in this collection
  447. if (logger.isDebugEnabled()) {
  448. logger.debug("building patch component for collection "
  449. + collection);
  450. }
  451. try {
  452. for (Document document : sbb.getDataSourceSbbInterface()
  453. .getDocuments(collection, true)) {
  454. DocumentSelector documentSelector = new DocumentSelector(
  455. document.getCollection(),
  456. document.getDocumentName());
  457. try {
  458. patchComponents.add(XCAP_DIFF_PATCH_BUILDER
  459. .getDocumentPatchComponentBuilder()
  460. .buildPatchComponent(
  461. documentSelector.toString(), null,
  462. document.getETag(), null));
  463. } catch (BuildPatchException e) {
  464. logger.error(e.getMessage(), e);
  465. }
  466. }
  467. } catch (Exception e) {
  468. logger.error(e.getMessage(), e);
  469. }
  470. }
  471. // now individual docs
  472. for (DocumentSelector documentSelector : subscriptions
  473. .getDocumentSubscriptions()) {
  474. if (logger.isDebugEnabled()) {
  475. logger.debug("building patch component for document subscription "
  476. + documentSelector);
  477. }
  478. Document document = null;
  479. try {
  480. document = sbb.getDataSourceSbbInterface().getDocument(
  481. documentSelector);
  482. } catch (InternalServerErrorException e) {
  483. logger.error(e);
  484. }
  485. if (document != null) {
  486. try {
  487. patchComponents.add(XCAP_DIFF_PATCH_BUILDER
  488. .getDocumentPatchComponentBuilder()
  489. .buildPatchComponent(documentSelector.toString(),
  490. null, document.getETag(), null));
  491. } catch (BuildPatchException e) {
  492. logger.error(e.getMessage(), e);
  493. }
  494. }
  495. }
  496. // now document nodes
  497. Document document = null;
  498. NodeSelector nodeSelector = null;
  499. for (NodeSubscription nodeSubscription : subscriptions
  500. .getNodeSubscriptions()) {
  501. if (logger.isDebugEnabled()) {
  502. logger.debug("building patch component for node subscription "
  503. + nodeSubscription);
  504. }
  505. try {
  506. document = sbb.getDataSourceSbbInterface().getDocument(
  507. nodeSubscription.getDocumentSelector());
  508. } catch (InternalServerErrorException e) {
  509. logger.error(e);
  510. }
  511. boolean exists = document != null;
  512. if (exists) {
  513. // find out if the node exists
  514. nodeSelector = nodeSubscription.getNodeSelector();
  515. org.w3c.dom.Document documentDOM = null;
  516. try {
  517. documentDOM = document.getAsDOMDocument();
  518. } catch (InternalServerErrorException e) {
  519. logger.error(e.getMessage(), e);
  520. continue;
  521. }
  522. AppUsage appUsage = APP_USAGE_MANAGEMENT
  523. .getAppUsage(nodeSubscription.getDocumentSelector()
  524. .getAUID());
  525. if (appUsage == null) {
  526. logger.error("app usage not available, unable to process node subscription "
  527. + nodeSubscription);
  528. continue;
  529. }
  530. nodeSelector.getNamespaceContext().setDefaultDocNamespace(
  531. appUsage.getDefaultDocumentNamespace());
  532. final XPath xpath = DomUtils.XPATH_FACTORY.newXPath();
  533. xpath.setNamespaceContext(nodeSelector.getNamespaceContext());
  534. Node node = null;
  535. try {
  536. // exec query to get element
  537. final NodeList nodeList = (NodeList) xpath.evaluate(
  538. nodeSelector.toStringWithEmptyPrefix(),
  539. documentDOM, XPathConstants.NODESET);
  540. if (nodeList.getLength() == 0) {
  541. // node does not exists
  542. if (logger.isDebugEnabled()) {
  543. try {
  544. logger.debug("no node matches expression "
  545. + nodeSelector
  546. .toStringWithEmptyPrefix()
  547. + " in doc: \n"
  548. + TextWriter.toString(documentDOM));
  549. } catch (TransformerException e) {
  550. logger.error(e);
  551. }
  552. }
  553. exists = false;
  554. } else {
  555. node = nodeList.item(0);
  556. }
  557. } catch (XPathExpressionException e) {
  558. logger.error(
  559. "failed to find node " + nodeSelector + "in doc "
  560. + nodeSubscription.getDocumentSelector(), e);
  561. continue;
  562. }
  563. try {
  564. if (nodeSubscription.getNodeSelector()
  565. .getTerminalSelector() != null) {
  566. if (exists) {
  567. patchComponents.add(XCAP_DIFF_PATCH_BUILDER
  568. .getAttributePatchComponentBuilder()
  569. .buildPatchComponent(
  570. nodeSubscription.getSel(),
  571. ((Attr) node).getValue(),
  572. nodeSelector.getNamespaceContext()
  573. .getNamespaces()));
  574. } else {
  575. patchComponents.add(XCAP_DIFF_PATCH_BUILDER
  576. .getAttributePatchComponentBuilder()
  577. .buildPatchComponent(
  578. nodeSubscription.getSel(),
  579. nodeSelector.getNamespaceContext()
  580. .getNamespaces()));
  581. }
  582. } else {
  583. if (exists) {
  584. patchComponents.add(XCAP_DIFF_PATCH_BUILDER
  585. .getElementPatchComponentBuilder()
  586. .buildPatchComponent(
  587. nodeSubscription.getSel(),
  588. node,
  589. nodeSelector.getNamespaceContext()
  590. .getNamespaces()));
  591. } else {
  592. patchComponents.add(XCAP_DIFF_PATCH_BUILDER
  593. .getElementPatchComponentBuilder()
  594. .buildPatchComponent(
  595. nodeSubscription.getSel(),
  596. false,
  597. nodeSelector.getNamespaceContext()
  598. .getNamespaces()));
  599. }
  600. }
  601. } catch (BuildPatchException e) {
  602. logger.error(e.getMessage(), e);
  603. continue;
  604. }
  605. }
  606. }
  607. // build notify content
  608. org.w3c.dom.Document xcapDiff = null;
  609. try {
  610. xcapDiff = XCAP_DIFF_PATCH_BUILDER.buildPatch(
  611. XDM_SERVER_CONFIGURATION.getFullXcapRoot(), patchComponents
  612. .toArray(new Element[patchComponents.size()]));
  613. if (logger.isInfoEnabled()) {
  614. try {
  615. logger.info("xcap diff notify content for subscription "
  616. + subscription + ":\n"
  617. + TextWriter.toString(xcapDiff));
  618. } catch (TransformerException e) {
  619. logger.error(e.getMessage(), e);
  620. }
  621. }
  622. } catch (BuildPatchException e) {
  623. logger.error("failed to build xcap diff patch", e);
  624. return null;
  625. }
  626. return new NotifyContent(xcapDiff, getXcapDiffContentTypeHeader(sbb),
  627. null);
  628. }
  629. public Object filterContentPerSubscriber(Subscription subscription,
  630. Object unmarshalledContent,
  631. XcapDiffSubscriptionControlSbbInterface sbb) {
  632. return unmarshalledContent;
  633. }
  634. /**
  635. *
  636. * @param event
  637. * @param aci
  638. * @param sbb
  639. */
  640. public void documentUpdated(DocumentUpdatedEvent event,
  641. ActivityContextInterface aci,
  642. XcapDiffSubscriptionControlSbbInterface sbb) {
  643. if (logger.isDebugEnabled()) {
  644. logger.debug("document " + event.getDocumentSelector()
  645. + " updated.");
  646. }
  647. SubscriptionsMap subscriptionsMap = sbb.getSubscriptionsMap();
  648. if (subscriptionsMap == null) {
  649. return;
  650. }
  651. String eventCollection = null;
  652. Object activity = aci.getActivity();
  653. if (activity instanceof CollectionActivity) {
  654. eventCollection = ((CollectionActivity) activity).getCollection();
  655. if (logger.isDebugEnabled()) {
  656. logger.debug("document update in a collection activity -> "
  657. + eventCollection);
  658. }
  659. }
  660. for (Subscriptions s : subscriptionsMap.getSubscriptions()) {
  661. if (logger.isDebugEnabled()) {
  662. logger.debug("processing subscription " + s.getKey());
  663. }
  664. if (eventCollection != null) {
  665. // event was fired in a collection, look for subscriptions with
  666. // such collection
  667. for (String collection : s.getCollectionSubscriptions()) {
  668. if (eventCollection.equals(collection)) {
  669. if (logger.isDebugEnabled()) {
  670. logger.debug("subscription " + s.getKey()
  671. + " is subscribed to collection "
  672. + collection
  673. + ", requesting notification...");
  674. }
  675. notifySubscriber(s, event, sbb);
  676. }
  677. }
  678. } else {
  679. // event was fired in the document activity, no need to check
  680. // collections
  681. for (DocumentSelector ds : s.getDocumentSubscriptions()) {
  682. if (ds.equals(event.getDocumentSelector())) {
  683. if (logger.isDebugEnabled()) {
  684. logger.debug("subscription " + s.getKey()
  685. + " is subscribed to document " + ds
  686. + ", requesting notification...");
  687. }
  688. notifySubscriber(s, event, sbb);
  689. }
  690. }
  691. for (NodeSubscription ns : s.getNodeSubscriptions()) {
  692. if (ns.getDocumentSelector().equals(
  693. event.getDocumentSelector())) {
  694. if (logger.isDebugEnabled()) {
  695. logger.debug("subscription " + s.getKey()
  696. + " is subscribed to " + ns
  697. + ", requesting notification...");
  698. }
  699. // tell underlying sip event framework to notify
  700. // subscriber
  701. try {
  702. sbb.getParentSbb().notifySubscriber(
  703. s.getKey(),
  704. new NotifyContent(
  705. event.getNodeXcapDiff(ns),
  706. getXcapDiffContentTypeHeader(sbb),
  707. null));
  708. } catch (BuildPatchException e) {
  709. logger.error(
  710. "Failed to build and notify xcap diff for subscription "
  711. + s + " and node "
  712. + ns.getNodeSelector()
  713. + " in document "
  714. + event.getDocumentSelector(), e);
  715. }
  716. }
  717. }
  718. }
  719. }
  720. }
  721. private void notifySubscriber(Subscriptions s, DocumentUpdatedEvent event,
  722. XcapDiffSubscriptionControlSbbInterface sbb) {
  723. // tell underlying sip event framework to notify
  724. // subscriber
  725. try {
  726. if (s.getDiffProcessing() == null
  727. || s.getDiffProcessing() == DiffProcessing.NoPatching) {
  728. sbb.getParentSbb().notifySubscriber(
  729. s.getKey(),
  730. new NotifyContent(event.getDocXcapDiff(false),
  731. getXcapDiffContentTypeHeader(sbb), null));
  732. } else {
  733. sbb.getParentSbb().notifySubscriber(
  734. s.getKey(),
  735. new NotifyContent(event.getDocXcapDiff(true),
  736. getXcapDiffContentTypeHeader(sbb),
  737. EVENT_HEADER_PATCHING_PARAMS));
  738. }
  739. } catch (BuildPatchException e) {
  740. logger.error(
  741. "Failed to build and notify xcap diff for subscription "
  742. + s + " and document "
  743. + event.getDocumentSelector(), e);
  744. }
  745. }
  746. private static Logger logger = Logger
  747. .getLogger(XcapDiffSubscriptionControl.class);
  748. }