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

/servers/sip-presence/xdm/server/core/xcap-control/sbb/src/main/java/org/openxdm/xcap/server/slee/RequestProcessorSbb.java

http://mobicents.googlecode.com/
Java | 2047 lines | 1530 code | 161 blank | 356 comment | 386 complexity | df16add4c4bbea412252986dec8421a3 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

Large files files are truncated, but you can click here to view the full file

  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;
  23. import java.io.InputStream;
  24. import java.io.Reader;
  25. import java.io.StringReader;
  26. import java.util.Collection;
  27. import java.util.HashMap;
  28. import java.util.Map;
  29. import javax.naming.Context;
  30. import javax.naming.InitialContext;
  31. import javax.naming.NamingException;
  32. import javax.slee.ActivityContextInterface;
  33. import javax.slee.RolledBackContext;
  34. import javax.slee.SbbContext;
  35. import javax.slee.facilities.Tracer;
  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.mobicents.slee.xdm.server.ServerConfiguration;
  41. import org.mobicents.xdm.common.util.dom.DocumentCloner;
  42. import org.mobicents.xdm.common.util.dom.DomUtils;
  43. import org.mobicents.xdm.server.appusage.AppUsage;
  44. import org.mobicents.xdm.server.appusage.AppUsageManagement;
  45. import org.mobicents.xdm.server.appusage.AuthorizationPolicy;
  46. import org.openxdm.xcap.common.error.BadRequestException;
  47. import org.openxdm.xcap.common.error.CannotDeleteConflictException;
  48. import org.openxdm.xcap.common.error.CannotInsertConflictException;
  49. import org.openxdm.xcap.common.error.ConflictException;
  50. import org.openxdm.xcap.common.error.ConstraintFailureConflictException;
  51. import org.openxdm.xcap.common.error.InternalServerErrorException;
  52. import org.openxdm.xcap.common.error.MethodNotAllowedException;
  53. import org.openxdm.xcap.common.error.NoParentConflictException;
  54. import org.openxdm.xcap.common.error.NotAuthorizedRequestException;
  55. import org.openxdm.xcap.common.error.NotFoundException;
  56. import org.openxdm.xcap.common.error.NotUTF8ConflictException;
  57. import org.openxdm.xcap.common.error.NotValidXMLFragmentConflictException;
  58. import org.openxdm.xcap.common.error.NotXMLAttributeValueConflictException;
  59. import org.openxdm.xcap.common.error.PreconditionFailedException;
  60. import org.openxdm.xcap.common.error.SchemaValidationErrorConflictException;
  61. import org.openxdm.xcap.common.error.UniquenessFailureConflictException;
  62. import org.openxdm.xcap.common.error.UnsupportedMediaTypeException;
  63. import org.openxdm.xcap.common.etag.ETagGenerator;
  64. import org.openxdm.xcap.common.resource.AttributeResource;
  65. import org.openxdm.xcap.common.resource.DocumentResource;
  66. import org.openxdm.xcap.common.resource.ElementResource;
  67. import org.openxdm.xcap.common.resource.NamespaceBindings;
  68. import org.openxdm.xcap.common.uri.AttributeSelector;
  69. import org.openxdm.xcap.common.uri.DocumentSelector;
  70. import org.openxdm.xcap.common.uri.ElementSelector;
  71. import org.openxdm.xcap.common.uri.ElementSelectorStep;
  72. import org.openxdm.xcap.common.uri.ElementSelectorStepByAttr;
  73. import org.openxdm.xcap.common.uri.ElementSelectorStepByPos;
  74. import org.openxdm.xcap.common.uri.ElementSelectorStepByPosAttr;
  75. import org.openxdm.xcap.common.uri.NodeSelector;
  76. import org.openxdm.xcap.common.uri.ParseException;
  77. import org.openxdm.xcap.common.uri.Parser;
  78. import org.openxdm.xcap.common.uri.ResourceSelector;
  79. import org.openxdm.xcap.common.uri.TerminalSelector;
  80. import org.openxdm.xcap.common.xml.NamespaceContext;
  81. import org.openxdm.xcap.common.xml.TextWriter;
  82. import org.openxdm.xcap.common.xml.XMLValidator;
  83. import org.openxdm.xcap.server.etag.ETagValidator;
  84. import org.openxdm.xcap.server.result.CreatedWriteResult;
  85. import org.openxdm.xcap.server.result.OKWriteResult;
  86. import org.openxdm.xcap.server.result.ReadResult;
  87. import org.openxdm.xcap.server.result.WriteResult;
  88. import org.openxdm.xcap.server.slee.resource.datasource.DataSourceSbbInterface;
  89. import org.w3c.dom.Attr;
  90. import org.w3c.dom.Document;
  91. import org.w3c.dom.Element;
  92. import org.w3c.dom.NamedNodeMap;
  93. import org.w3c.dom.Node;
  94. import org.w3c.dom.NodeList;
  95. public abstract class RequestProcessorSbb implements RequestProcessor,
  96. javax.slee.Sbb {
  97. private SbbContext sbbContext = null;
  98. private static Tracer logger;
  99. private DataSourceSbbInterface dataSourceSbbInterface;
  100. private AppUsageDataSourceImpl appUsageDataSource;
  101. private static final ServerConfiguration CONFIGURATION = ServerConfiguration
  102. .getInstance();
  103. private static final AppUsageManagement APPUSAGE_MANAGEMENT = AppUsageManagement
  104. .getInstance();
  105. /**
  106. * Called when an sbb object is instantied and enters the pooled state.
  107. */
  108. public void setSbbContext(SbbContext context) {
  109. this.sbbContext = context;
  110. if (logger == null) {
  111. logger = sbbContext.getTracer(this.getClass().getSimpleName());
  112. }
  113. try {
  114. Context myEnv = (Context) new InitialContext()
  115. .lookup("java:comp/env");
  116. dataSourceSbbInterface = (DataSourceSbbInterface) myEnv
  117. .lookup("slee/resources/openxdm/datasource/sbbrainterface");
  118. appUsageDataSource = new AppUsageDataSourceImpl(
  119. dataSourceSbbInterface);
  120. } catch (NamingException e) {
  121. logger.severe("Can't set sbb context.", e);
  122. }
  123. }
  124. public void unsetSbbContext() {
  125. this.sbbContext = null;
  126. }
  127. public void sbbCreate() throws javax.slee.CreateException {
  128. }
  129. public void sbbPostCreate() throws javax.slee.CreateException {
  130. }
  131. public void sbbActivate() {
  132. }
  133. public void sbbPassivate() {
  134. }
  135. public void sbbRemove() {
  136. }
  137. public void sbbLoad() {
  138. }
  139. public void sbbStore() {
  140. }
  141. public void sbbExceptionThrown(Exception exception, Object event,
  142. ActivityContextInterface activity) {
  143. if (logger.isFineEnabled())
  144. logger.fine("sbbExceptionThrown(exception=" + exception.toString()
  145. + ",event=" + event.toString() + ",activity="
  146. + activity.toString() + ")");
  147. }
  148. public void sbbRolledBack(RolledBackContext sbbRolledBack) {
  149. if (logger.isFineEnabled())
  150. logger.fine("sbbRolledBack(sbbRolledBack="
  151. + sbbRolledBack.toString() + ")");
  152. }
  153. /*
  154. * (non-Javadoc)
  155. *
  156. * @see
  157. * org.openxdm.xcap.server.slee.RequestProcessor#delete(org.openxdm.xcap
  158. * .common.uri.ResourceSelector, org.openxdm.xcap.server.etag.ETagValidator,
  159. * java.lang.String, java.lang.String)
  160. */
  161. @Override
  162. public WriteResult delete(ResourceSelector resourceSelector,
  163. ETagValidator eTagValidator, String xcapRoot,
  164. String authenticatedUser) throws NotFoundException,
  165. InternalServerErrorException, BadRequestException,
  166. CannotDeleteConflictException, PreconditionFailedException,
  167. MethodNotAllowedException, SchemaValidationErrorConflictException,
  168. UniquenessFailureConflictException,
  169. ConstraintFailureConflictException, NotAuthorizedRequestException {
  170. if (logger.isFineEnabled())
  171. logger.fine("deleting " + resourceSelector);
  172. AppUsage appUsage = null;
  173. try {
  174. // parse document selector
  175. final DocumentSelector documentSelector = DocumentSelector
  176. .valueOf(resourceSelector.getDocumentSelector());
  177. // get app usage
  178. appUsage = APPUSAGE_MANAGEMENT.getAppUsage(documentSelector
  179. .getAUID());
  180. if (appUsage == null) {
  181. // throw exception
  182. if (logger.isFineEnabled())
  183. logger.fine("appusage " + documentSelector.getAUID()
  184. + " not found");
  185. throw new NotFoundException();
  186. }
  187. // authorize user
  188. if (authenticatedUser != null
  189. && !appUsage.getAuthorizationPolicy().isAuthorized(
  190. authenticatedUser,
  191. AuthorizationPolicy.Operation.DELETE,
  192. documentSelector, appUsageDataSource)) {
  193. throw new NotAuthorizedRequestException();
  194. }
  195. // get document
  196. org.openxdm.xcap.common.datasource.Document document = dataSourceSbbInterface
  197. .getDocument(documentSelector);
  198. if (document == null) {
  199. // throw exception
  200. if (logger.isFineEnabled())
  201. logger.fine("document " + documentSelector + " not found");
  202. throw new NotFoundException();
  203. }
  204. if (logger.isFineEnabled())
  205. logger.fine("document " + documentSelector + " found");
  206. // check document etag
  207. if (eTagValidator != null) {
  208. eTagValidator.validate(document.getETag());
  209. if (logger.isFineEnabled())
  210. logger.fine("document " + documentSelector
  211. + " etag validated");
  212. } else {
  213. if (logger.isFineEnabled())
  214. logger.fine("document " + documentSelector
  215. + " etag validation not required");
  216. }
  217. if (resourceSelector.getNodeSelector() != null) {
  218. // elem, attr or namespace bind
  219. // parse node selector
  220. final NodeSelector nodeSelector = Parser.parseNodeSelector(
  221. resourceSelector.getNodeSelector(),
  222. resourceSelector.getNamespaceContext());
  223. if (logger.isFineEnabled())
  224. logger.fine("node selector " + nodeSelector
  225. + " found and parsed");
  226. // config namespace context
  227. final NamespaceContext namespaceContext = resourceSelector
  228. .getNamespaceContext();
  229. namespaceContext.setDefaultDocNamespace(appUsage
  230. .getDefaultDocumentNamespace());
  231. // clone doc
  232. final Document newDocumentDOM = DocumentCloner.clone(document
  233. .getAsDOMDocument());
  234. // get element
  235. final Element newElement = getElementForDeleteOrGet(
  236. newDocumentDOM, nodeSelector, false);
  237. // parse element selector
  238. final ElementSelector elementSelector = Parser
  239. .parseElementSelector(nodeSelector.getElementSelector());
  240. if (nodeSelector.getTerminalSelector() != null) {
  241. // delete attr or namespace bind
  242. // parse terminal selector
  243. TerminalSelector terminalSelector = Parser
  244. .parseTerminalSelector(nodeSelector
  245. .getTerminalSelector());
  246. if (logger.isFineEnabled())
  247. logger.fine("terminal selector " + terminalSelector
  248. + " found and parsed");
  249. if (terminalSelector instanceof AttributeSelector) {
  250. return deleteAttribute(document, newDocumentDOM,
  251. newElement, documentSelector, nodeSelector,
  252. elementSelector,
  253. (AttributeSelector) terminalSelector, appUsage,
  254. true);
  255. } else {
  256. // namespace selector, only GET method is allowed
  257. if (logger.isFineEnabled())
  258. logger.fine("terminal selector "
  259. + terminalSelector
  260. + " is a namespace selector, not allowed on delete");
  261. Map<String, String> map = new HashMap<String, String>();
  262. map.put("Allow", "GET");
  263. throw new MethodNotAllowedException(map);
  264. }
  265. } else {
  266. // delete element
  267. return deleteElement(document, newDocumentDOM, newElement,
  268. documentSelector, nodeSelector, elementSelector,
  269. appUsage, true);
  270. }
  271. } else {
  272. return deleteDocument(document, documentSelector, appUsage,
  273. true);
  274. }
  275. } catch (ParseException e) {
  276. if (logger.isFineEnabled())
  277. logger.fine("error parsing uri, returning not found");
  278. throw new NotFoundException();
  279. }
  280. }
  281. private WriteResult deleteDocument(
  282. org.openxdm.xcap.common.datasource.Document document,
  283. DocumentSelector documentSelector, AppUsage appUsage,
  284. boolean processResourceInterdependencies)
  285. throws InternalServerErrorException,
  286. ConstraintFailureConflictException,
  287. UniquenessFailureConflictException,
  288. SchemaValidationErrorConflictException {
  289. if (logger.isFineEnabled())
  290. logger.fine("deleting document " + documentSelector);
  291. if (logger.isFineEnabled())
  292. logger.fine("processing app usage resource interdependencies for "
  293. + documentSelector);
  294. // process resource interdependencies for the request app usage
  295. if (processResourceInterdependencies) {
  296. try {
  297. appUsage.processResourceInterdependenciesOnDeleteDocument(
  298. document.getAsDOMDocument(), documentSelector, this,
  299. appUsageDataSource);
  300. } catch (SchemaValidationErrorConflictException e) {
  301. // must rollback all changes in datasource
  302. if (!sbbContext.getRollbackOnly())
  303. sbbContext.setRollbackOnly();
  304. throw e;
  305. } catch (UniquenessFailureConflictException e) {
  306. if (!sbbContext.getRollbackOnly())
  307. sbbContext.setRollbackOnly();
  308. throw e;
  309. } catch (ConstraintFailureConflictException e) {
  310. if (!sbbContext.getRollbackOnly())
  311. sbbContext.setRollbackOnly();
  312. throw e;
  313. } catch (InternalServerErrorException e) {
  314. if (!sbbContext.getRollbackOnly())
  315. sbbContext.setRollbackOnly();
  316. throw e;
  317. }
  318. }
  319. if (logger.isFineEnabled())
  320. logger.fine("app usage resource interdependencies processed for "
  321. + documentSelector);
  322. // delete document
  323. try {
  324. dataSourceSbbInterface.deleteDocument(documentSelector,
  325. appUsage.getDefaultDocumentNamespace(), document);
  326. } catch (InternalServerErrorException e) {
  327. if (!sbbContext.getRollbackOnly())
  328. sbbContext.setRollbackOnly();
  329. throw e;
  330. }
  331. if (logger.isFineEnabled())
  332. logger.fine(documentSelector.toString() + " deleted");
  333. return new OKWriteResult();
  334. }
  335. private WriteResult deleteElement(
  336. final org.openxdm.xcap.common.datasource.Document oldDocument,
  337. final Document newDocumentDOM, final Element newElement,
  338. final DocumentSelector documentSelector,
  339. final NodeSelector nodeSelector,
  340. final ElementSelector elementSelector, AppUsage appUsage,
  341. boolean processResourceInterdependencies)
  342. throws InternalServerErrorException, NotFoundException,
  343. CannotDeleteConflictException,
  344. SchemaValidationErrorConflictException, BadRequestException,
  345. UniquenessFailureConflictException,
  346. ConstraintFailureConflictException {
  347. if (logger.isFineEnabled())
  348. logger.fine("deleting element " + elementSelector + " in document "
  349. + documentSelector);
  350. // check cannot delete
  351. ElementSelectorStep lastElementSelectorStep = elementSelector
  352. .getLastStep();
  353. if (lastElementSelectorStep instanceof ElementSelectorStepByPosAttr) {
  354. // need to check if it's the last sibring
  355. // with the same name and attr value
  356. ElementSelectorStepByPosAttr elementSelectorStepByPosAttr = (ElementSelectorStepByPosAttr) lastElementSelectorStep;
  357. if (elementSelectorStepByPosAttr.getName().equals("*")) {
  358. if (logger.isFineEnabled())
  359. logger.fine("element selector by attr and pos with wildcard name");
  360. // all elements wildcard
  361. Element siblingElement = newElement;
  362. while ((siblingElement = (Element) siblingElement
  363. .getNextSibling()) != null) {
  364. // get attribute with same name
  365. Attr siblingElementAttr = siblingElement
  366. .getAttributeNode(elementSelectorStepByPosAttr
  367. .getAttrName());
  368. // check if it has the same value
  369. if (siblingElementAttr != null
  370. && siblingElementAttr.getValue()
  371. .equals(elementSelectorStepByPosAttr
  372. .getAttrValue())) {
  373. // we have a sibling with the
  374. // same attribute with the same
  375. // value, so when we delete the
  376. // element the uri points to
  377. // this one
  378. if (logger.isFineEnabled())
  379. logger.fine("sibling element with same attr name and value, cannot delete");
  380. throw new CannotDeleteConflictException();
  381. }
  382. }
  383. } else {
  384. if (logger.isFineEnabled())
  385. logger.fine("element selector by attr and pos without wildcard name");
  386. Element siblingElement = newElement;
  387. while ((siblingElement = (Element) siblingElement
  388. .getNextSibling()) != null) {
  389. if (newElement.getNodeName().compareTo(
  390. siblingElement.getNodeName()) == 0
  391. && newElement.getNamespaceURI().compareTo(
  392. siblingElement.getNamespaceURI()) == 0) {
  393. // sibling with the same name
  394. // get attribute with same name
  395. Attr siblingElementAttr = siblingElement
  396. .getAttributeNode(elementSelectorStepByPosAttr
  397. .getAttrName());
  398. // check if it has the same
  399. // value
  400. if (siblingElementAttr != null
  401. && siblingElementAttr.getValue().equals(
  402. elementSelectorStepByPosAttr
  403. .getAttrValue())) {
  404. // we have a sibling with
  405. // the same attribute with
  406. // the same value, so when
  407. // we delete the element the
  408. // uri points to this one
  409. if (logger.isFineEnabled())
  410. logger.fine("sibling element with same attr name and value, cannot delete");
  411. throw new CannotDeleteConflictException();
  412. }
  413. }
  414. }
  415. }
  416. } else if (lastElementSelectorStep instanceof ElementSelectorStepByPos) {
  417. ElementSelectorStepByPos elementSelectorStepByPos = (ElementSelectorStepByPos) lastElementSelectorStep;
  418. /*
  419. * In particular, if a DELETE operation refers to an element by name
  420. * and position alone (parent/elname[n]), this is permitted only
  421. * when the element to be deleted is the last element amongst all
  422. * its siblings with that name. Similarly, if a DELETE operation
  423. * refers to an element by position alone (parent/*[n]), this is
  424. * permitted only when the elemented to be deleted is the last
  425. * amongst all sibling elements, regardless of name.
  426. */
  427. // find out if it's the last sibling
  428. if (elementSelectorStepByPos.getName().equals("*")) {
  429. if (logger.isFineEnabled())
  430. logger.fine("element selector by pos with wildcard name");
  431. if (newElement.getNextSibling() != null) {
  432. // not the last * sibling
  433. if (logger.isFineEnabled())
  434. logger.fine("not the last * sibling, cannot delete");
  435. throw new CannotDeleteConflictException();
  436. }
  437. } else {
  438. if (logger.isFineEnabled())
  439. logger.fine("element selector by pos without wildcard name");
  440. // search a next sibling with the same
  441. // name
  442. Element siblingElement = newElement;
  443. while ((siblingElement = (Element) siblingElement
  444. .getNextSibling()) != null) {
  445. if (newElement.getNodeName().compareTo(
  446. siblingElement.getNodeName()) == 0
  447. && newElement.getNamespaceURI().compareTo(
  448. siblingElement.getNamespaceURI()) == 0) {
  449. if (logger.isFineEnabled())
  450. logger.fine("sibling element with same name and ns after the selected element,cannot delete");
  451. throw new CannotDeleteConflictException();
  452. }
  453. }
  454. }
  455. }
  456. if (logger.isFineEnabled())
  457. logger.fine("element deleted");
  458. // the element can be deleted
  459. newElement.getParentNode().removeChild(newElement);
  460. if (logger.isFineEnabled())
  461. logger.fine("validating document after delete");
  462. // validate the updated document against it's schema
  463. appUsage.validateSchema(newDocumentDOM);
  464. if (logger.isFineEnabled())
  465. logger.fine("checking app usage constraints and resource interdependencies...");
  466. // verify app usage constraints
  467. appUsage.checkConstraintsOnDelete(newDocumentDOM,
  468. CONFIGURATION.getXcapRoot(), documentSelector,
  469. appUsageDataSource);
  470. // create new etag
  471. String newETag = ETagGenerator.generate(documentSelector.toString());
  472. // process resource interdependencies for the request app usage
  473. if (processResourceInterdependencies) {
  474. try {
  475. appUsage.processResourceInterdependenciesOnDeleteElement(
  476. newElement, documentSelector, newETag, nodeSelector,
  477. elementSelector, this, appUsageDataSource);
  478. } catch (SchemaValidationErrorConflictException e) {
  479. if (!sbbContext.getRollbackOnly())
  480. sbbContext.setRollbackOnly();
  481. throw e;
  482. } catch (UniquenessFailureConflictException e) {
  483. if (!sbbContext.getRollbackOnly())
  484. sbbContext.setRollbackOnly();
  485. throw e;
  486. } catch (ConstraintFailureConflictException e) {
  487. if (!sbbContext.getRollbackOnly())
  488. sbbContext.setRollbackOnly();
  489. throw e;
  490. } catch (InternalServerErrorException e) {
  491. if (!sbbContext.getRollbackOnly())
  492. sbbContext.setRollbackOnly();
  493. throw e;
  494. }
  495. }
  496. // update data source with document
  497. try {
  498. String newDocumentString = TextWriter.toString(newDocumentDOM);
  499. dataSourceSbbInterface.updateElement(documentSelector,
  500. appUsage.getDefaultDocumentNamespace(), oldDocument,
  501. newDocumentDOM, newDocumentString, newETag, nodeSelector,
  502. newElement, null);
  503. if (logger.isFineEnabled())
  504. logger.fine("document updated in data source");
  505. } catch (Exception e) {
  506. if (!sbbContext.getRollbackOnly())
  507. sbbContext.setRollbackOnly();
  508. throw new InternalServerErrorException(
  509. "Failed to serialize resulting dom document to string");
  510. }
  511. if (logger.isFineEnabled())
  512. logger.fine(elementSelector.toString() + " element in "
  513. + documentSelector + " deleted");
  514. return new OKWriteResult(newETag);
  515. }
  516. private WriteResult deleteAttribute(
  517. final org.openxdm.xcap.common.datasource.Document oldDocument,
  518. final Document newDocumentDOM, final Element newElement,
  519. final DocumentSelector documentSelector,
  520. final NodeSelector nodeSelector,
  521. final ElementSelector elementSelector,
  522. final AttributeSelector attributeSelector, final AppUsage appUsage,
  523. boolean processResourceInterdependencies)
  524. throws InternalServerErrorException, NotFoundException,
  525. SchemaValidationErrorConflictException, BadRequestException,
  526. UniquenessFailureConflictException,
  527. ConstraintFailureConflictException {
  528. if (logger.isFineEnabled())
  529. logger.fine("deleting attribute " + attributeSelector.getAttName()
  530. + " from element " + elementSelector + " in document "
  531. + documentSelector);
  532. final String attrName = attributeSelector.getAttName();
  533. String oldAttrValue = null;
  534. // note that getAttribute returns "" for a non existent attribute
  535. if (newElement.hasAttribute(attrName)) {
  536. oldAttrValue = newElement.getAttribute(attrName);
  537. }
  538. if (oldAttrValue != null) {
  539. // exists, delete it
  540. newElement.removeAttribute(attrName);
  541. if (logger.isFineEnabled())
  542. logger.fine("attribute found and deleted");
  543. } else {
  544. // does not exists
  545. if (logger.isFineEnabled())
  546. logger.fine("attribute to delete not found");
  547. throw new NotFoundException();
  548. }
  549. if (logger.isFineEnabled())
  550. logger.fine("validating document after delete");
  551. // validate the updated document against it's schema
  552. appUsage.validateSchema(newDocumentDOM);
  553. if (logger.isFineEnabled())
  554. logger.fine("checking app usage constraints and resource interdependencies...");
  555. // verify app usage constraints
  556. appUsage.checkConstraintsOnDelete(newDocumentDOM,
  557. CONFIGURATION.getXcapRoot(), documentSelector,
  558. appUsageDataSource);
  559. // create new etag
  560. String newETag = ETagGenerator.generate(documentSelector.toString());
  561. // process resource interdependencies
  562. if (processResourceInterdependencies) {
  563. try {
  564. appUsage.processResourceInterdependenciesOnDeleteAttribute(
  565. documentSelector, newETag, nodeSelector,
  566. elementSelector, attributeSelector, this,
  567. appUsageDataSource);
  568. } catch (SchemaValidationErrorConflictException e) {
  569. if (!sbbContext.getRollbackOnly())
  570. sbbContext.setRollbackOnly();
  571. throw e;
  572. } catch (UniquenessFailureConflictException e) {
  573. if (!sbbContext.getRollbackOnly())
  574. sbbContext.setRollbackOnly();
  575. throw e;
  576. } catch (ConstraintFailureConflictException e) {
  577. if (!sbbContext.getRollbackOnly())
  578. sbbContext.setRollbackOnly();
  579. throw e;
  580. } catch (InternalServerErrorException e) {
  581. if (!sbbContext.getRollbackOnly())
  582. sbbContext.setRollbackOnly();
  583. throw e;
  584. }
  585. }
  586. if (logger.isFineEnabled())
  587. logger.fine("app usage resource interdependencies processed for "
  588. + documentSelector);
  589. // update data source with document
  590. try {
  591. String newDocumentString = TextWriter.toString(newDocumentDOM);
  592. dataSourceSbbInterface.updateAttribute(documentSelector,
  593. appUsage.getDefaultDocumentNamespace(), oldDocument,
  594. newDocumentDOM, newDocumentString, newETag, nodeSelector,
  595. attributeSelector, oldAttrValue, null);
  596. if (logger.isFineEnabled())
  597. logger.fine("document updated in data source");
  598. } catch (Exception e) {
  599. if (!sbbContext.getRollbackOnly())
  600. sbbContext.setRollbackOnly();
  601. throw new InternalServerErrorException(
  602. "Failed to serialize resulting dom document to string");
  603. }
  604. return new OKWriteResult(newETag);
  605. }
  606. /*
  607. * (non-Javadoc)
  608. *
  609. * @see
  610. * org.openxdm.xcap.server.slee.RequestProcessor#get(org.openxdm.xcap.common
  611. * .uri.ResourceSelector, java.lang.String)
  612. */
  613. @Override
  614. public ReadResult get(ResourceSelector resourceSelector,
  615. String authenticatedUser) throws NotFoundException,
  616. InternalServerErrorException, BadRequestException,
  617. NotAuthorizedRequestException {
  618. AppUsage appUsage = null;
  619. try {
  620. // parse document parent String
  621. DocumentSelector documentSelector = DocumentSelector
  622. .valueOf(resourceSelector.getDocumentSelector());
  623. // get app usage from cache
  624. appUsage = APPUSAGE_MANAGEMENT.getAppUsage(documentSelector
  625. .getAUID());
  626. if (appUsage == null) {
  627. // throw exception
  628. if (logger.isFineEnabled())
  629. logger.fine("appusage not found");
  630. throw new NotFoundException();
  631. }
  632. // authorize user
  633. if (authenticatedUser != null
  634. && !appUsage.getAuthorizationPolicy().isAuthorized(
  635. authenticatedUser,
  636. AuthorizationPolicy.Operation.GET,
  637. documentSelector, appUsageDataSource)) {
  638. throw new NotAuthorizedRequestException();
  639. }
  640. // get document
  641. org.openxdm.xcap.common.datasource.Document document = dataSourceSbbInterface
  642. .getDocument(documentSelector);
  643. if (document == null) {
  644. // throw exception
  645. if (logger.isFineEnabled())
  646. logger.fine("document not found");
  647. throw new NotFoundException();
  648. }
  649. if (logger.isFineEnabled())
  650. logger.fine("document found");
  651. // get document's etag
  652. String eTag = document.getETag();
  653. // check node selector string from resource selector
  654. if (resourceSelector.getNodeSelector() != null) {
  655. // elem, attrib or namespace bind
  656. // parse node selector
  657. NodeSelector nodeSelector = Parser.parseNodeSelector(
  658. resourceSelector.getNodeSelector(),
  659. resourceSelector.getNamespaceContext());
  660. if (logger.isFineEnabled())
  661. logger.fine("node selector found and parsed");
  662. // create xpath
  663. XPath xpath = DomUtils.XPATH_FACTORY.newXPath();
  664. // add a namespace context to xpath to resolve bindings
  665. // config namespace context
  666. final NamespaceContext nsContext = resourceSelector
  667. .getNamespaceContext();
  668. nsContext.setDefaultDocNamespace(appUsage
  669. .getDefaultDocumentNamespace());
  670. xpath.setNamespaceContext(nsContext);
  671. if (logger.isFineEnabled())
  672. logger.fine("xpath initiated with namespace context");
  673. // get document as dom
  674. org.w3c.dom.Document domDocument = document.getAsDOMDocument();
  675. final Element element = getElementForDeleteOrGet(domDocument,
  676. nodeSelector, false);
  677. if (nodeSelector.getTerminalSelector() != null) {
  678. // parse terminal selector
  679. TerminalSelector terminalSelector = Parser
  680. .parseTerminalSelector(nodeSelector
  681. .getTerminalSelector());
  682. if (logger.isFineEnabled())
  683. logger.fine("terminal selector found and parsed");
  684. if (terminalSelector instanceof AttributeSelector) {
  685. // attribute selector, get attribute
  686. if (logger.isFineEnabled())
  687. logger.fine("terminal selector is an attribute selector");
  688. Attr attr = element
  689. .getAttributeNode(((AttributeSelector) terminalSelector)
  690. .getAttName());
  691. if (attr != null) {
  692. // exists, return its value
  693. if (logger.isFineEnabled())
  694. logger.fine("attribute found, returning result");
  695. return new ReadResult(eTag, new AttributeResource(
  696. attr.getNodeValue()));
  697. } else {
  698. // does not exists
  699. if (logger.isFineEnabled())
  700. logger.fine("attribute to retreive not found");
  701. throw new NotFoundException();
  702. }
  703. } else {
  704. // namespace selector, get namespace bindings
  705. if (logger.isFineEnabled())
  706. logger.fine("terminal selector is a namespace selector");
  707. return new ReadResult(eTag, getNamespaceBindings(
  708. element, DomUtils.getElementName(element),
  709. nsContext.getNamespaces()));
  710. }
  711. } else {
  712. // element
  713. if (logger.isFineEnabled())
  714. logger.fine("terminal selector not found, returining result with the element found");
  715. return new ReadResult(eTag, new ElementResource(
  716. TextWriter.toString(element)));
  717. }
  718. } else {
  719. // no node selector, just get the document
  720. if (logger.isFineEnabled())
  721. logger.fine("node selector not found, returning the document");
  722. return new ReadResult(eTag, new DocumentResource(
  723. document.getAsString(), appUsage.getMimetype()));
  724. }
  725. } catch (ParseException e) {
  726. if (logger.isFineEnabled())
  727. logger.fine("error in parsing uri.");
  728. throw new NotFoundException();
  729. } catch (TransformerException e) {
  730. logger.severe("unable to transform dom element to text.", e);
  731. throw new InternalServerErrorException(e.getMessage());
  732. }
  733. }
  734. private NamespaceBindings getNamespaceBindings(Node element,
  735. String elementName, Map<String, String> namespacesToGet)
  736. throws NotFoundException {
  737. boolean done = false;
  738. // init result namespaces map
  739. Map<String, String> result = new HashMap<String, String>();
  740. // remove empty prefix from "namespaces to get" map
  741. namespacesToGet.remove("");
  742. // create set of namespaces uri to get
  743. Collection<String> namespacesUris = namespacesToGet.values();
  744. while (done == false && element.getNodeType() == Node.ELEMENT_NODE) {
  745. // get element attributes
  746. NamedNodeMap elementAttributes = element.getAttributes();
  747. // process each one
  748. for (int i = 0; i < elementAttributes.getLength(); i++) {
  749. Node attributeNode = elementAttributes.item(i);
  750. if (attributeNode.getNodeName().compareTo("xmlns") == 0
  751. || attributeNode.getPrefix().compareTo("xmlns") == 0) {
  752. // its a namespace
  753. if (namespacesUris.contains(attributeNode.getNodeValue())) {
  754. // it was requested, add it to the result map
  755. result.put(attributeNode.getNodeName(),
  756. attributeNode.getNodeValue());
  757. if (result.size() == namespacesUris.size()) {
  758. done = true;
  759. break;
  760. }
  761. }
  762. }
  763. }
  764. // move to parent
  765. element = element.getParentNode();
  766. }
  767. if (!done) {
  768. // at least one was not found
  769. if (logger.isFineEnabled())
  770. logger.fine("didn't found any namespace binding, returning not found");
  771. throw new NotFoundException();
  772. } else {
  773. // return namespace bindings
  774. if (logger.isFineEnabled())
  775. logger.fine("found namespace binding(s)");
  776. return new NamespaceBindings(elementName, result);
  777. }
  778. }
  779. /*
  780. * (non-Javadoc)
  781. *
  782. * @see
  783. * org.openxdm.xcap.server.slee.RequestProcessor#put(org.openxdm.xcap.common
  784. * .uri.ResourceSelector, java.lang.String, java.io.InputStream,
  785. * org.openxdm.xcap.server.etag.ETagValidator, java.lang.String,
  786. * java.lang.String)
  787. */
  788. @Override
  789. public WriteResult put(ResourceSelector resourceSelector, String mimetype,
  790. InputStream contentStream, ETagValidator eTagValidator,
  791. String xcapRoot, String authenticatedUser)
  792. throws ConflictException, MethodNotAllowedException,
  793. UnsupportedMediaTypeException, InternalServerErrorException,
  794. PreconditionFailedException, BadRequestException,
  795. NotAuthorizedRequestException {
  796. DocumentSelector documentSelector = null;
  797. try {
  798. // parse document parent String
  799. documentSelector = DocumentSelector.valueOf(resourceSelector
  800. .getDocumentSelector());
  801. if (logger.isFineEnabled())
  802. logger.fine("document selector found and parsed: "
  803. + documentSelector);
  804. } catch (ParseException e) {
  805. // invalid document selector, throw no parent exception
  806. if (logger.isFineEnabled())
  807. logger.fine("failed to parse document selector, returning no parent conflict");
  808. throw new NoParentConflictException(xcapRoot);
  809. }
  810. // get app usage
  811. final AppUsage appUsage = APPUSAGE_MANAGEMENT
  812. .getAppUsage(documentSelector.getAUID());
  813. if (appUsage == null) {
  814. // throw exception
  815. if (logger.isFineEnabled())
  816. logger.fine("appusage " + documentSelector.getAUID()
  817. + " not found");
  818. throw new NoParentConflictException(xcapRoot);
  819. }
  820. if (logger.isFineEnabled())
  821. logger.fine("appusage " + documentSelector.getAUID() + " found");
  822. // authorize user
  823. if (authenticatedUser != null
  824. && !appUsage.getAuthorizationPolicy().isAuthorized(
  825. authenticatedUser, AuthorizationPolicy.Operation.PUT,
  826. documentSelector, appUsageDataSource)) {
  827. throw new NotAuthorizedRequestException();
  828. }
  829. // try to get document's resource
  830. org.openxdm.xcap.common.datasource.Document oldDocument = dataSourceSbbInterface
  831. .getDocument(documentSelector);
  832. if (oldDocument != null) {
  833. // validate etag if needed
  834. if (eTagValidator != null) {
  835. eTagValidator.validate(oldDocument.getETag());
  836. if (logger.isFineEnabled())
  837. logger.fine("document etag validated");
  838. } else {
  839. if (logger.isFineEnabled())
  840. logger.fine("document etag validation not required");
  841. }
  842. }
  843. if (resourceSelector.getNodeSelector() != null) {
  844. // put elem, attr, namespaces
  845. if (oldDocument == null) {
  846. // doc does not exists, throw exception
  847. throw new NoParentConflictException(xcapRoot
  848. + documentSelector.getCollection());
  849. }
  850. NodeSelector nodeSelector = null;
  851. ElementSelector elementSelector = null;
  852. try {
  853. // parse node selector
  854. nodeSelector = Parser.parseNodeSelector(
  855. resourceSelector.getNodeSelector(),
  856. resourceSelector.getNamespaceContext());
  857. elementSelector = Parser.parseElementSelector(nodeSelector
  858. .getElementSelector());
  859. if (logger.isFineEnabled())
  860. logger.fine("node selector found and parsed: "
  861. + nodeSelector);
  862. } catch (ParseException e) {
  863. // unable to parse the node selector, throw no parent
  864. // exception with the document as the existent ancestor
  865. if (logger.isFineEnabled())
  866. logger.fine("unable to parse the node selector or element selector, returning no parent conflict with the document as the existent ancestor");
  867. throw new NoParentConflictException(xcapRoot
  868. + resourceSelector.getDocumentSelector());
  869. }
  870. // config namespace context
  871. final NamespaceContext namespaceContext = resourceSelector
  872. .getNamespaceContext();
  873. namespaceContext.setDefaultDocNamespace(appUsage
  874. .getDefaultDocumentNamespace());
  875. // clone doc
  876. final Document newDocumentDOM = DocumentCloner.clone(oldDocument
  877. .getAsDOMDocument());
  878. // get element
  879. final Element element = getElementForPut(documentSelector,
  880. newDocumentDOM, nodeSelector, false);
  881. if (nodeSelector.getTerminalSelector() != null) {
  882. // put attr or namespaces
  883. try {
  884. TerminalSelector terminalSelector = Parser
  885. .parseTerminalSelector(nodeSelector
  886. .getTerminalSelector());
  887. if (terminalSelector instanceof AttributeSelector) {
  888. // verify mimetype
  889. if (mimetype == null
  890. || !mimetype.equals(AttributeResource.MIMETYPE)) {
  891. // mimetype is not correct
  892. throw new UnsupportedMediaTypeException();
  893. }
  894. // read attribute value (checking if is utf-8 too)
  895. final String newAttributeValue = XMLValidator
  896. .getUTF8String(contentStream);
  897. if (logger.isFineEnabled())
  898. logger.fine("attr content is utf-8");
  899. return putAttribute(oldDocument, newDocumentDOM,
  900. element, documentSelector, nodeSelector,
  901. elementSelector,
  902. (AttributeSelector) terminalSelector,
  903. newAttributeValue, appUsage, true);
  904. } else {
  905. if (logger.isFineEnabled())
  906. logger.fine("terminal selector is a namespace selector, not allowed on put");
  907. Map<String, String> map = new HashMap<String, String>();
  908. map.put("Allow", "GET");
  909. throw new MethodNotAllowedException(map);
  910. }
  911. } catch (ParseException e) {
  912. // unable to parse the node selector, throw no parent
  913. // exception with the document as the existent ancestor
  914. if (logger.isFineEnabled())
  915. logger.fine("unable to parse the node selector or element selector, returning no parent conflict with the document as the existent ancestor");
  916. throw new NoParentConflictException(xcapRoot
  917. + resourceSelector.getDocumentSelector());
  918. }
  919. } else {
  920. // check mimetype
  921. if (mimetype == null
  922. || !mimetype.equals(ElementResource.MIMETYPE)) {
  923. // mimetype is not correct
  924. throw new UnsupportedMediaTypeException();
  925. }
  926. // read and verify if content value is utf-8
  927. final String newElementAsString = XMLValidator
  928. .getUTF8String(contentStream);
  929. if (logger.isFineEnabled())
  930. logger.fine("content is utf-8");
  931. // create XML fragment node
  932. final Element newElement = XMLValidator
  933. .getWellFormedDocumentFragment(new StringReader(
  934. newElementAsString));
  935. if (logger.isFineEnabled())
  936. logger.fine("content is well formed document fragment");
  937. return putElement(oldDocument, newDocumentDOM, element,
  938. documentSelector, nodeSelector, elementSelector,
  939. newElement, appUsage, true);
  940. }
  941. } else {
  942. // put document
  943. // validate mimetype
  944. if (mimetype == null || !mimetype.equals(appUsage.getMimetype())) {
  945. // mimetype is not valid
  946. if (logger.isFineEnabled())
  947. logger.fine("invalid mimetype, does not matches the app usage");
  948. throw new UnsupportedMediaTypeException();
  949. }
  950. // verify if content is utf-8
  951. final Reader utf8reader = XMLValidator.getUTF8Reader(contentStream);
  952. if (logger.isFineEnabled())
  953. logger.fine("document content is utf-8");
  954. // build new document
  955. final Document newDomDocument = XMLValidator
  956. .getWellFormedDocument(utf8reader);
  957. if (logger.isFineEnabled())
  958. logger.fine("document content is well formed");
  959. return putDocument(documentSelector, oldDocument, newDomDocument,
  960. appUsage, true);
  961. }
  962. }
  963. // -- APP USAGE REQUEST PROCESSOR METHODS
  964. private WriteResult putDocument(DocumentSelector documentSelector,
  965. org.openxdm.xcap.common.datasource.Document oldDocument,
  966. Document newDocumentDOM, AppUsage appUsage,
  967. boolean processResourceInterdependencies) throws ConflictException,
  968. MethodNotAllowedException, UnsupportedMediaTypeException,
  969. InternalServerErrorException, PreconditionFailedException,
  970. BadRequestException, NotAuthorizedRequestException {
  971. Document oldDomDocument = null;
  972. if (oldDocument == null) { // DOCUMENTS DOES NOT EXIST
  973. if (logger.isFineEnabled())
  974. logger.fine("document not found");
  975. } else {
  976. // DOCUMENT EXISTS
  977. if (logger.isFineEnabled())
  978. logger.fine("document found");
  979. oldDomDocument = oldDocument.getAsDOMDocument();
  980. }
  981. // validate the updated document against it's schema
  982. appUsage.validateSchema(newDocumentDOM);
  983. if (logger.isFineEnabled())
  984. logger.fine("document validated by schema");
  985. // verify app usage constraints
  986. appUsage.checkConstraintsOnPut(newDocumentDOM,
  987. CONFIGURATION.getXcapRoot(), documentSelector,
  988. appUsageDataSource);
  989. if (logger.isFineEnabled())
  990. logger.fine("app usage constraints checked");
  991. // create new document etag
  992. String newETag = ETagGenerator.generate(documentSelector.toString());
  993. if (logger.isFineEnabled())
  994. logger.fine("new document etag generated");
  995. // process resource interdependencies for the request app usage
  996. if (processResourceInterdependencies) {
  997. try {
  998. appUsage.processResourceInterdependenciesOnPutDocument(
  999. oldDomDocument, newDocumentDOM, documentSelector,
  1000. newETag, this, appUsageDataSource);
  1001. } catch (SchemaValidationErrorConflictException e) {
  1002. if (!sbbContext.getRollbackOnly())
  1003. sbbContext.setRollbackOnly();
  1004. throw e;
  1005. } catch (UniquenessFailureConflictException e) {
  1006. if (!sbbContext.getRollbackOnly())
  1007. sbbContext.setRollbackOnly();
  1008. throw e;
  1009. } catch (InternalServerErrorException e) {
  1010. if (!sbbContext.getRollbackOnly())
  1011. sbbContext.setRollbackOnly();
  1012. throw e;
  1013. } catch (ConstraintFailureConflictException e) {
  1014. if (!sbbContext.getRollbackOnly())
  1015. sbbContext.setRollbackOnly();
  1016. throw e;
  1017. }
  1018. }
  1019. if (logger.isFineEnabled())
  1020. logger.fine("app usage resource interdependencies processed");
  1021. // update data source with document
  1022. try {
  1023. String newDocumentString = TextWriter.toString(newDocumentDOM);
  1024. if (oldDocument == null) {
  1025. dataSourceSbbInterface.createDocument(documentSelector,
  1026. appUsage.getDefaultDocumentNamespace(), newDocumentDOM,
  1027. newDocumentString, newETag);
  1028. if (logger.isFineEnabled())
  1029. logger.fine("document created in data source");
  1030. } else {
  1031. dataSourceSbbInterface.updateDocument(documentSelector,
  1032. appUsage.getDefaultDocumentNamespace(), oldDocument,
  1033. newDocumentDOM, newDocumentString, newETag);
  1034. if (logger.isFineEnabled())
  1035. logger.fine("document updated in data source");
  1036. }
  1037. } catch (Exception e) {
  1038. logger.severe(
  1039. "Failed to serialize resulting dom document to string", e);
  1040. throw new InternalServerErrorException(
  1041. "Failed to serialize resulting dom document to string", e);
  1042. }
  1043. return oldDocument == null ? new CreatedWriteResult(newETag)
  1044. : new OKWriteResult(newETag);
  1045. }
  1046. private WriteResult putElement(
  1047. final org.openxdm.xcap.common.datasource.Document oldDocument,
  1048. final Document newDocumentDOM, final Element oldElement,
  1049. final DocumentSelector documentSelector,
  1050. final NodeSelector nodeSelector,
  1051. final ElementSelector elementSelector, Element newElement,
  1052. final AppUsage appUsage, boolean processResourceInterdependencies)
  1053. throws InternalServerErrorException, NoParentConflictException,
  1054. SchemaValidationErrorConflictException,
  1055. UniquenessFailureConflictException,
  1056. ConstraintFailureConflictException, CannotInsertConflictException,
  1057. NotValidXMLFragmentConflictException, NotUTF8ConflictException,
  1058. BadRequestException, NotAuthorizedRequestException {
  1059. if (logger.isFineEnabled())
  1060. logger.fine("putting element " + elementSelector + " in "
  1061. + documentSelector);
  1062. if (oldElement != null) {
  1063. // replace element
  1064. // verify if cannot insert
  1065. ElementSelectorStep lastElementSelectorStep = elementSelector
  1066. .getLastStep();
  1067. // if element's tag name is not equal to
  1068. // this step's name then cannot insert
  1069. if (!newElement.getTagName().equals(
  1070. lastElementSelectorStep.getName())) {
  1071. if (logger.isFineEnabled())
  1072. logger.fine("element's tag name is not equal to this step's name, cannot insert");
  1073. throw new CannotInsertConflictException();
  1074. }
  1075. if (lastElementSelectorStep instanceof ElementSelectorStepByAttr) {
  1076. ElementSelectorStepByAttr elementSelectorStepByAttr = (ElementSelectorStepByAttr) lastElementSelectorStep;
  1077. // check attr value
  1078. String elementAttrValue = newElement
  1079. .getAttribute(elementSelectorStepByAttr.getAttrName());
  1080. if (elementAttrValue == null
  1081. || !elementAttrValue.equals(elementSelectorStepByAttr
  1082. .getAttrValue())) {
  1083. if (logger.isFineEnabled())
  1084. logger.fine("element selector's last step has an attr and it's new value changes this attr value, cannot insert");
  1085. throw new CannotInsertConflictException();
  1086. }
  1087. }
  1088. // import the element node
  1089. newElement = (Element) newDocumentDOM.importNode(newElement, true);
  1090. // replace node
  1091. oldElement.getParentNode().replaceChild(newElement, oldElement);
  1092. if (logger.isFineEnabled())
  1093. logger.fine("element " + elementSelector + " replaced in "
  1094. + documentSelector);
  1095. } else {
  1096. // new element
  1097. final Element elementParent = getElementForPut(documentSelector,
  1098. newDocumentDOM, nodeSelector, true);
  1099. if (elementParent == null) {
  1100. if (logger.isFineEnabled())
  1101. logger.fine("element parent not found, returning no parent conflict");
  1102. XPath xpath = DomUtils.XPATH_FACTORY.newXPath();
  1103. xpath.setNamespaceContext(nodeSelector.getNamespaceContext());
  1104. throw new NoParentConflictException(getElementExistentAncestor(
  1105. CONFIGURATION.getXcapRoot(),
  1106. documentSelector.toString(),
  1107. nodeSelector.getElementParentSelectorWithEmptyPrefix(),
  1108. newDocumentDOM, xpath));
  1109. } else {
  1110. // put new element
  1111. newElement = (Element) newDocumentDOM.importNode(newElement,
  1112. true);
  1113. // get element step
  1114. ElementSelectorStep elementLastStep = elementSelector
  1115. .getLastStep();
  1116. // get element name & namespace
  1117. String elementNamespace = null;
  1118. String elementName = null;
  1119. String elementNamePrefix = elementLastStep.getPrefix();
  1120. if (elementNamePrefix != null) {
  1121. // get element name without prefix
  1122. elementName = elementLastStep.getNameWithoutPrefix();
  1123. // and get namespace
  1124. elementNamespace = nodeSelector.getNamespaceContext()
  1125. .getNamespaceURI(elementNamePrefix);
  1126. } else {
  1127. // get element name without prefix
  1128. elementName = elementLastStep.getName();
  1129. // and get namespace
  1130. elementNamespace = nodeSelector.getNamespaceContext()
  1131. .getNamespaceURI("");
  1132. }
  1133. // if new element node name is not the same as in the uri then
  1134. // cannot
  1135. // insert
  1136. if (!newElement.getNodeName().equals(elementName)) {
  1137. if (logger.isFineEnabled())
  1138. logger.fine("element node name is not the same as in the uri, cannot insert");
  1139. throw new CannotInsertConflictException();
  1140. }
  1141. if (elementLastStep instanceof ElementSelectorStepByPos) {
  1142. // position defined
  1143. if (logger.isFineEnabled())
  1144. logger.fine("element selector's last step with position defined");
  1145. ElementSelectorStepByPos elementSelectorStepByPos = (ElementSelectorStepByPos) elementLastStep;
  1146. if (elementSelectorStepByPos.getPos() == 1) {
  1147. // POS = 1
  1148. if (!(elementLastStep instanceof ElementSelectorStepByPosAttr)) {
  1149. // NO ATTR TEST, *[1] e name[1], either way, just
  1150. // append to
  1151. // the parent
  1152. if (logger.isFineEnabled())
  1153. logger.fine("element selector's last step without attr test defined");
  1154. elementParent.appendChild(newElement);
  1155. if (logger.isFineEnabled())
  1156. logger.fine("element appended to parent");
  1157. } else {
  1158. // ATTR TEST
  1159. if (logger.isFineEnabled())
  1160. logger.fine("element selector's last step with attr test defined");
  1161. // verify that the element has this step atribute
  1162. // with this
  1163. // step attribute value, if not it cannot insert
  1164. ElementSelectorStepByPosAttr elementSelectorStepByPosAttr = (ElementSelectorStepByPosAttr) elementLastStep;
  1165. String elementAttrName = elementSelectorStepByPosAttr
  1166. .getAttrName();
  1167. String elementAttrValue = newElement
  1168. .getAttribute(elementAttrName);
  1169. if (elementAttrValue == null
  1170. || !elementAttrValue
  1171. .equals(elementSelectorStepByPosAttr
  1172. .getAttrValue())) {
  1173. if (logger.isFineEnabled())
  1174. logger.fine("element selector's last step has an atribute and the attribute value does not matches, cannot insert");
  1175. throw new CannotInsertConflictException();
  1176. }
  1177. // *[1][attr-test], insert before the first element
  1178. // name[1][attr-test], insert before the first
  1179. // element with
  1180. // same name
  1181. NodeList elementParentChilds = elementParent
  1182. .getChildNodes();
  1183. boolean inserted = false;
  1184. for (int i = 0; i < elementParentChilds.getLength(); i++) {
  1185. if (elementParentChilds.item(i) instanceof Element
  1186. && ((elementName
  1187. .equals(elementParentChilds
  1188. .item(i).getNodeName()) && elementParentChilds
  1189. .item(i).getNamespaceURI()
  1190. .equals(elementNamespace)) || (elementName
  1191. .equals("*")))) {
  1192. elementParent.insertBefore(newElement,
  1193. elementParentChilds.item(i));
  1194. if (logger.isFineEnabled())
  1195. logger.fine("element inserted at pos "
  1196. + i);
  1197. inserted = true;
  1198. break;
  1199. }
  1200. }
  1201. if (!inserted) {
  1202. // didn't found an element just append to parent
  1203. elementParent.appendChild(newElement);
  1204. if (logger.isFineEnabled())
  1205. logger.fine("element appended to parent");
  1206. }
  1207. }
  1208. }
  1209. else {
  1210. // POS > 1, must find the pos-1 element and insert after
  1211. if (elementLastStep instanceof ElementSelectorStepByPosAttr) {
  1212. // ATTR TEST
  1213. if (logger.isFineEnabled())
  1214. logger.fine("element selector's last step with attr test defined");
  1215. // verify that the element has this…

Large files files are truncated, but you can click here to view the full file