PageRenderTime 44ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/servers/sip-presence/xdm/server/appusages/rls-services/bean/src/main/java/org/openxdm/xcap/server/slee/appusage/rlsservices/RLSServicesAppUsage.java

http://mobicents.googlecode.com/
Java | 449 lines | 305 code | 39 blank | 105 comment | 57 complexity | fe8a499f2c974733f011bfde4d001773 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.openxdm.xcap.server.slee.appusage.rlsservices;
  23. import java.net.URI;
  24. import java.net.URLDecoder;
  25. import java.util.HashSet;
  26. import java.util.Set;
  27. import javax.xml.validation.Validator;
  28. import org.apache.log4j.Logger;
  29. import org.mobicents.xdm.common.util.dom.DomUtils;
  30. import org.mobicents.xdm.server.appusage.AppUsage;
  31. import org.mobicents.xdm.server.appusage.AppUsageDataSource;
  32. import org.mobicents.xdm.server.appusage.AppUsageRequestProcessor;
  33. import org.openxdm.xcap.common.error.ConstraintFailureConflictException;
  34. import org.openxdm.xcap.common.error.InternalServerErrorException;
  35. import org.openxdm.xcap.common.error.NotAuthorizedRequestException;
  36. import org.openxdm.xcap.common.error.SchemaValidationErrorConflictException;
  37. import org.openxdm.xcap.common.error.UniquenessFailureConflictException;
  38. import org.openxdm.xcap.common.uri.AttributeSelector;
  39. import org.openxdm.xcap.common.uri.DocumentSelector;
  40. import org.openxdm.xcap.common.uri.ElementSelector;
  41. import org.openxdm.xcap.common.uri.NodeSelector;
  42. import org.openxdm.xcap.common.xml.NamespaceContext;
  43. import org.openxdm.xcap.server.slee.appusage.resourcelists.ResourceListsAppUsage;
  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. public class RLSServicesAppUsage extends AppUsage {
  49. public static final String ID = "rls-services";
  50. public static final String DEFAULT_DOC_NAMESPACE = "urn:ietf:params:xml:ns:rls-services";
  51. public static final String MIMETYPE = "application/rls-services+xml";
  52. private static final Logger logger = Logger
  53. .getLogger(RLSServicesAppUsage.class);
  54. private final NamespaceContext namespaceContext;
  55. private final boolean validateUniquenessContraints;
  56. public RLSServicesAppUsage(Validator schemaValidator, boolean validateUniquenessContraints) {
  57. super(ID, DEFAULT_DOC_NAMESPACE, MIMETYPE, schemaValidator,
  58. new RLSServicesAuthorizationPolicy());
  59. namespaceContext = new NamespaceContext();
  60. namespaceContext.setDefaultDocNamespace(DEFAULT_DOC_NAMESPACE);
  61. this.validateUniquenessContraints = validateUniquenessContraints;
  62. }
  63. private static final String SERVICE_ELEMENT_NAME = "service";
  64. private static final String URI_ATTRIBUTE_NAME = "uri";
  65. private Set<String> getServiceURIs(Document document)
  66. throws UniquenessFailureConflictException {
  67. Set<String> serviceURIs = new HashSet<String>();
  68. NodeList nodeList = document.getDocumentElement().getChildNodes();
  69. Node node = null;
  70. for (int i = 0; i < nodeList.getLength(); i++) {
  71. node = nodeList.item(i);
  72. if (DomUtils.isElementNamed(node, SERVICE_ELEMENT_NAME)) {
  73. Element element = (Element) node;
  74. if (!serviceURIs.add(element.getAttribute(URI_ATTRIBUTE_NAME))) {
  75. throw new UniquenessFailureConflictException();
  76. }
  77. }
  78. }
  79. return serviceURIs;
  80. }
  81. static boolean isUserIndexDoc(DocumentSelector documentSelector) {
  82. if (!documentSelector.getDocumentName().equals("index")) {
  83. return false;
  84. }
  85. return documentSelector.getCollection().equals(
  86. new StringBuilder("rls-services/users/").append(
  87. documentSelector.getUser()).toString());
  88. }
  89. private void checkServiceExists(String uri, AppUsageDataSource dataSource)
  90. throws UniquenessFailureConflictException,
  91. InternalServerErrorException {
  92. // fetch all user docs
  93. DocumentSelector ds = null;
  94. NodeList nodeList = null;
  95. Node node = null;
  96. for (org.openxdm.xcap.common.datasource.Document document : dataSource
  97. .getDocuments("rls-services/users", true)) {
  98. ds = new DocumentSelector(document.getCollection(),
  99. document.getDocumentName());
  100. if (RLSServicesAppUsage.isUserIndexDoc(ds)) {
  101. // only process index docs at the user dir collection
  102. // get all 2nd level elements
  103. nodeList = document.getAsDOMDocument().getDocumentElement()
  104. .getChildNodes();
  105. for (int i = 0; i < nodeList.getLength(); i++) {
  106. node = nodeList.item(i);
  107. if (DomUtils.isElementNamed(node, SERVICE_ELEMENT_NAME)) {
  108. // rls-services/service element
  109. if (((Element) node).getAttribute(URI_ATTRIBUTE_NAME)
  110. .equals(uri)) {
  111. // uri attribute matches, thus new service not
  112. // unique
  113. throw new UniquenessFailureConflictException();
  114. }
  115. }
  116. }
  117. }
  118. }
  119. }
  120. private void checkServicesExists(Set<String> uris,
  121. AppUsageDataSource dataSource)
  122. throws UniquenessFailureConflictException,
  123. InternalServerErrorException {
  124. // fetch all user docs
  125. DocumentSelector ds = null;
  126. NodeList nodeList = null;
  127. Node node = null;
  128. for (org.openxdm.xcap.common.datasource.Document document : dataSource
  129. .getDocuments("rls-services/users", true)) {
  130. ds = new DocumentSelector(document.getCollection(),
  131. document.getDocumentName());
  132. if (RLSServicesAppUsage.isUserIndexDoc(ds)) {
  133. // only process index docs at the user dir collection
  134. // get all 2nd level elements
  135. nodeList = document.getAsDOMDocument().getDocumentElement()
  136. .getChildNodes();
  137. for (int i = 0; i < nodeList.getLength(); i++) {
  138. node = nodeList.item(i);
  139. if (DomUtils.isElementNamed(node, SERVICE_ELEMENT_NAME)) {
  140. // rls-services/service element
  141. if (uris.contains(((Element) node)
  142. .getAttribute(URI_ATTRIBUTE_NAME))) {
  143. // uri attribute matches, thus new service not
  144. // unique
  145. throw new UniquenessFailureConflictException();
  146. }
  147. }
  148. }
  149. }
  150. }
  151. }
  152. @Override
  153. public void processResourceInterdependenciesOnPutAttribute(
  154. String oldAttrValue, String newAttrValue,
  155. DocumentSelector documentSelector, String newETag,
  156. NodeSelector nodeSelector, ElementSelector elementSelector,
  157. AttributeSelector attributeSelector,
  158. AppUsageRequestProcessor requestProcessor,
  159. AppUsageDataSource dataSource)
  160. throws SchemaValidationErrorConflictException,
  161. UniquenessFailureConflictException, InternalServerErrorException,
  162. ConstraintFailureConflictException {
  163. if (logger.isDebugEnabled()) {
  164. logger.debug("processResourceInterdependenciesOnPutAttribute( oldAttrValue = "
  165. + oldAttrValue
  166. + ", newAttrValue = "
  167. + newAttrValue
  168. + ", documentSelector = "
  169. + documentSelector
  170. + ", elementSelector = "
  171. + elementSelector
  172. + ", attributeSelector = " + attributeSelector + " )");
  173. }
  174. if (!validateUniquenessContraints) {
  175. return;
  176. }
  177. if (!isUserIndexDoc(documentSelector)) {
  178. return;
  179. }
  180. if (elementSelector.getStepsSize() != 2
  181. || !attributeSelector.getAttName().equals("uri")) {
  182. // only the change of a service uri is relevant
  183. return;
  184. }
  185. // the new attr value is a new service uri, check it doesn't exists
  186. checkServiceExists(newAttrValue, dataSource);
  187. }
  188. @Override
  189. public void processResourceInterdependenciesOnPutElement(
  190. Element oldElement, Element newElement, Document document,
  191. DocumentSelector documentSelector, String newETag,
  192. NodeSelector nodeSelector, ElementSelector elementSelector,
  193. AppUsageRequestProcessor requestProcessor,
  194. AppUsageDataSource dataSource)
  195. throws SchemaValidationErrorConflictException,
  196. UniquenessFailureConflictException, InternalServerErrorException,
  197. ConstraintFailureConflictException {
  198. if (logger.isDebugEnabled()) {
  199. logger.debug("processResourceInterdependenciesOnPutElement( oldElement = "
  200. + oldElement
  201. + ", newElement = "
  202. + newElement
  203. + ", documentSelector = "
  204. + documentSelector
  205. + ", elementSelector = " + elementSelector + " )");
  206. }
  207. if (!validateUniquenessContraints) {
  208. return;
  209. }
  210. if (!isUserIndexDoc(documentSelector)) {
  211. return;
  212. }
  213. if (elementSelector.getStepsSize() > 2) {
  214. // only the change of a service uri is relevant
  215. return;
  216. } else if (elementSelector.getStepsSize() == 2) {
  217. // put of 1 service
  218. if (oldElement != null) {
  219. // update
  220. if (oldElement.getAttribute("uri").equals(
  221. newElement.getAttribute("uri"))) {
  222. // uri didn't change
  223. return;
  224. } else {
  225. // check if the new uri exists
  226. checkServiceExists(newElement.getAttribute("uri"),
  227. dataSource);
  228. }
  229. } else {
  230. // creation
  231. // check if the new uri exists
  232. checkServiceExists(newElement.getAttribute("uri"), dataSource);
  233. }
  234. } else {
  235. // put of all services, same as put of doc
  236. processResourceInterdependenciesOnPutDocument(dataSource
  237. .getDocument(documentSelector).getAsDOMDocument(),
  238. document, documentSelector, newETag, requestProcessor,
  239. dataSource);
  240. }
  241. }
  242. @Override
  243. public void processResourceInterdependenciesOnPutDocument(
  244. Document oldDocument, Document newDocument,
  245. DocumentSelector documentSelector, String newEtag,
  246. AppUsageRequestProcessor requestProcessor,
  247. AppUsageDataSource dataSource)
  248. throws SchemaValidationErrorConflictException,
  249. UniquenessFailureConflictException, InternalServerErrorException,
  250. ConstraintFailureConflictException {
  251. if (logger.isDebugEnabled()) {
  252. logger.debug("processResourceInterdependenciesOnPutDocument( oldDoc = "
  253. + oldDocument
  254. + ", newDoc = "
  255. + newDocument
  256. + ", documentSelector = " + documentSelector + " )");
  257. }
  258. if (!validateUniquenessContraints) {
  259. return;
  260. }
  261. if (!isUserIndexDoc(documentSelector)) {
  262. return;
  263. }
  264. if (oldDocument == null) {
  265. // insert
  266. checkServicesExists(getServiceURIs(newDocument), dataSource);
  267. } else {
  268. // update
  269. Set<String> newURIs = getServiceURIs(newDocument);
  270. newURIs.removeAll(getServiceURIs(oldDocument));
  271. checkServicesExists(newURIs, dataSource);
  272. }
  273. }
  274. @Override
  275. public void checkConstraintsOnPut(Document document, String xcapRoot,
  276. DocumentSelector documentSelector, AppUsageDataSource dataSource)
  277. throws UniquenessFailureConflictException,
  278. InternalServerErrorException, ConstraintFailureConflictException,
  279. NotAuthorizedRequestException {
  280. if (!documentSelector.isUserDocument()) {
  281. return;
  282. }
  283. super.checkConstraintsOnPut(document, xcapRoot, documentSelector,
  284. dataSource);
  285. /*
  286. * NOTE: the contraint below is ensured when (re)building the global doc
  287. *
  288. * "The URI in the "uri" attribute of the <service> element MUST be
  289. * unique amongst all other URIs in "uri" elements in any <service>
  290. * element in any document on a particular server. This uniqueness
  291. * constraint spans across XCAP roots."
  292. */
  293. /*
  294. * TODO ensure the uri is not a network resource, such as the uri of a
  295. * sip user
  296. *
  297. * "Furthermore, the URI MUST NOT correspond to an existing resource
  298. * within the domain of the URI. If a server is asked to set the URI to
  299. * something that already exists, the server MUST reject the request
  300. * with a 409, and use the mechanisms defined in [10] to suggest
  301. * alternate URIs that have not yet been allocated."
  302. */
  303. // get document's element childs
  304. NodeList childNodes = document.getDocumentElement().getChildNodes();
  305. // process each one
  306. for (int i = 0; i < childNodes.getLength(); i++) {
  307. Node childNode = childNodes.item(i);
  308. if (DomUtils.isElementNamed(childNode, "service")) {
  309. // service element
  310. // get childs
  311. NodeList serviceChildNodes = childNode.getChildNodes();
  312. // process each one
  313. for (int j = 0; j < serviceChildNodes.getLength(); j++) {
  314. Node serviceChildNode = serviceChildNodes.item(j);
  315. if (DomUtils.isElementNamed(serviceChildNode, "list")) {
  316. // list element
  317. /*
  318. * o In addition, an RLS services document can contain a
  319. * <list> element, which in turn can contain <entry>,
  320. * <entry-ref> and <external> elements. The constraints
  321. * defined for these elements in Section 3.4.7 MUST be
  322. * enforced.
  323. */
  324. ResourceListsAppUsage.checkNodeResourceListConstraints(
  325. serviceChildNode, false);
  326. } else if (DomUtils.isElementNamed(serviceChildNode,
  327. "resource-list")) {
  328. // resource-list element
  329. // flag setup
  330. boolean throwException = true;
  331. // node value is the uri to evaluate
  332. String resourceListUri = serviceChildNode
  333. .getTextContent().trim();
  334. try {
  335. // build uri
  336. URI uri = new URI(resourceListUri);
  337. String uriScheme = uri.getScheme();
  338. /*
  339. * The URI in a <resource-list> element MUST be an
  340. * absolute URI.
  341. */
  342. if (uriScheme != null
  343. && (uriScheme.equalsIgnoreCase("http") || uriScheme
  344. .equalsIgnoreCase("https"))) {
  345. // split string after "scheme://" to find path
  346. // segments
  347. String[] resourceListUriPaths = resourceListUri
  348. .substring(uriScheme.length() + 3)
  349. .split("/");
  350. for (int k = 0; k < resourceListUriPaths.length; k++) {
  351. /*
  352. * The server MUST verify that the URI path
  353. * contains "resource-lists" in the path
  354. * segment corresponding to the AUID.
  355. */
  356. if (resourceListUriPaths[k]
  357. .equals(ResourceListsAppUsage.ID)) {
  358. // found auid
  359. if (!resourceListUriPaths[k + 1]
  360. .equals("global")) {
  361. // not global
  362. /*
  363. * If the RLS services document is
  364. * within the XCAP user tree (as
  365. * opposed to the global tree), the
  366. * server MUST verify that the XUI
  367. * in the path is the same as the
  368. * XUI in the URI of to the
  369. * resource-list document.
  370. */
  371. // decode the candidate xui first
  372. String resourceListXUIDecoded = URLDecoder
  373. .decode(resourceListUriPaths[k + 2],
  374. "UTf-8");
  375. String requestXUI = documentSelector
  376. .getUser();
  377. if (resourceListXUIDecoded
  378. .equals(requestXUI)) {
  379. throwException = false;
  380. } else {
  381. logger.error("not the same xcap user id in request ("
  382. + requestXUI
  383. + ") and resource list ("
  384. + resourceListXUIDecoded
  385. + ") URIs");
  386. }
  387. break;
  388. } else {
  389. throwException = false;
  390. break;
  391. }
  392. }
  393. }
  394. }
  395. } catch (Exception e) {
  396. // ignore
  397. logger.error(e.getMessage(), e);
  398. }
  399. // throw exception if needed
  400. if (throwException) {
  401. throw new ConstraintFailureConflictException(
  402. "Bad URI in resource-list element >> "
  403. + resourceListUri);
  404. }
  405. }
  406. }
  407. }
  408. }
  409. }
  410. }