001/* 002 * Copyright 2010 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.externaldata.data.jcr; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023 024import javax.jcr.Node; 025import javax.jcr.NodeIterator; 026import javax.jcr.PathNotFoundException; 027import javax.jcr.Property; 028import javax.jcr.PropertyIterator; 029import javax.jcr.Repository; 030import javax.jcr.RepositoryException; 031import javax.jcr.Session; 032import javax.jcr.Value; 033 034import org.apache.avalon.framework.component.Component; 035import org.apache.avalon.framework.logger.AbstractLogEnabled; 036import org.apache.avalon.framework.service.ServiceException; 037import org.apache.avalon.framework.service.ServiceManager; 038import org.apache.avalon.framework.service.Serviceable; 039import org.apache.commons.lang.StringUtils; 040import org.apache.jackrabbit.JcrConstants; 041 042import org.ametys.core.datasource.DataSourceClientInteraction.DataSourceType; 043import org.ametys.core.observation.Event; 044import org.ametys.core.observation.ObservationManager; 045import org.ametys.core.ui.Callable; 046import org.ametys.core.user.CurrentUserProvider; 047import org.ametys.plugins.externaldata.cache.ObservationConstants; 048import org.ametys.plugins.externaldata.data.DataInclusionException; 049import org.ametys.plugins.externaldata.data.DataSourceFactory; 050import org.ametys.plugins.externaldata.data.DataSourceFactoryExtensionPoint; 051import org.ametys.plugins.externaldata.data.Query; 052import org.ametys.plugins.externaldata.data.Query.ResultType; 053import org.ametys.plugins.externaldata.data.QueryDao; 054import org.ametys.plugins.externaldata.data.QueryResult; 055import org.ametys.plugins.repository.AmetysObjectResolver; 056import org.ametys.plugins.repository.AmetysRepositoryException; 057import org.ametys.plugins.repository.ModifiableTraversableAmetysObject; 058import org.ametys.plugins.repository.RepositoryConstants; 059import org.ametys.plugins.repository.jcr.JCRAmetysObject; 060import org.ametys.plugins.repository.jcr.NameHelper; 061import org.ametys.plugins.repository.provider.AbstractRepository; 062import org.ametys.web.repository.site.SiteManager; 063 064/** 065 * JCR implementation of the Query DAO. 066 * This class manages DataSource and Query objects, storing them in the JCR repository. 067 */ 068public class JcrQueryDao extends AbstractLogEnabled implements QueryDao, Serviceable, Component 069{ 070 071 /** JCR relative path to root node. */ 072 public static final String ROOT_REPO = AmetysObjectResolver.ROOT_REPO; 073 074 /** Plugins root node name. */ 075 public static final String PLUGINS_NODE = "ametys-internal:plugins"; 076 077 /** Plugin root node name. */ 078 public static final String PLUGIN_NODE = "external-data"; 079 080 /** Data sources node name. */ 081 public static final String DATASOURCES_NODE = RepositoryConstants.NAMESPACE_PREFIX + ":datasources"; 082 083 /** Queries node name. */ 084 public static final String QUERIES_NODE = RepositoryConstants.NAMESPACE_PREFIX + ":queries"; 085 086 /** "Name" property name. */ 087 public static final String PROPERTY_NAME = RepositoryConstants.NAMESPACE_PREFIX + ":name"; 088 089 /** "Description" property name. */ 090 public static final String PROPERTY_DESCRIPTION = RepositoryConstants.NAMESPACE_PREFIX + ":description"; 091 092 /** "Type" property name. */ 093 public static final String PROPERTY_TYPE = RepositoryConstants.NAMESPACE_PREFIX + ":type"; 094 095 /** "Type" property name. */ 096 public static final String PROPERTY_DATASOURCE = RepositoryConstants.NAMESPACE_PREFIX + ":dataSourceId"; 097 098 /** Configuration properties prefix. */ 099 public static final String PROPERTY_CONF_PREFIX = RepositoryConstants.NAMESPACE_PREFIX + ":conf-"; 100 101 /** Query "query string" property name. */ 102 public static final String QUERY_PROPERTY_QUERYSTRING = RepositoryConstants.NAMESPACE_PREFIX + ":queryString"; 103 104 /** Query "parameters" property name. */ 105 public static final String QUERY_PROPERTY_PARAMETERS = RepositoryConstants.NAMESPACE_PREFIX + ":parameters"; 106 107 /** Query "resultType" property name. */ 108 public static final String QUERY_PROPERTY_RESULTTYPE = RepositoryConstants.NAMESPACE_PREFIX + ":resultType"; 109 110 /** The Data Source factory extension point. */ 111 protected DataSourceFactoryExtensionPoint _dataSourceFactoryEP; 112 113 /** The JCR repository. */ 114 protected Repository _repository; 115 116 /** The Site manager. */ 117 protected SiteManager _siteManager; 118 119 /** The current user provider */ 120 protected CurrentUserProvider _currentUserProvider; 121 122 /** The observation manager */ 123 protected ObservationManager _observationManager; 124 125 @Override 126 public void service(ServiceManager serviceManager) throws ServiceException 127 { 128 _dataSourceFactoryEP = (DataSourceFactoryExtensionPoint) serviceManager.lookup(DataSourceFactoryExtensionPoint.ROLE); 129 _repository = (Repository) serviceManager.lookup(AbstractRepository.ROLE); 130 _siteManager = (SiteManager) serviceManager.lookup(SiteManager.ROLE); 131 _currentUserProvider = (CurrentUserProvider) serviceManager.lookup(CurrentUserProvider.ROLE); 132 _observationManager = (ObservationManager) serviceManager.lookup(ObservationManager.ROLE); 133 } 134 135 @Override 136 public Map<String, Query> getQueries(String siteName) throws DataInclusionException 137 { 138 try 139 { 140 Map<String, Query> queries = new HashMap<>(); 141 142 Node queriesNode = _getQueriesNode(siteName); 143 144 NodeIterator queryNodes = queriesNode.getNodes(); 145 while (queryNodes.hasNext()) 146 { 147 Node node = queryNodes.nextNode(); 148 149 // Extract a Query object from the node and add it to the map. 150 Query query = _extractQuery(node); 151 queries.put(query.getId(), query); 152 } 153 154 return queries; 155 } 156 catch (RepositoryException e) 157 { 158 throw new DataInclusionException("Error getting the data sources", e); 159 } 160 } 161 162 @Override 163 public Map<String, Query> getQueries(String siteName, DataSourceType type) throws DataInclusionException 164 { 165 return getDataSourceQueries(siteName, null, type, null); 166 } 167 168 @Override 169 public Map<String, Query> getDataSourceQueries(String siteName, String dataSourceId) throws DataInclusionException 170 { 171 return getDataSourceQueries(siteName, dataSourceId, null); 172 } 173 174 @Override 175 public Map<String, Query> getDataSourceQueries(String siteName, String dataSourceId, ResultType resultType) throws DataInclusionException 176 { 177 return getDataSourceQueries(siteName, dataSourceId, null, resultType); 178 } 179 180 @Override 181 public Map<String, Query> getDataSourceQueries(String siteName, String dataSourceId, DataSourceType dataSourceType, ResultType resultType) throws DataInclusionException 182 { 183 try 184 { 185 // TODO Should be a made with a query instead of filtering. 186 Map<String, Query> queries = new HashMap<>(); 187 188 Node queriesNode = _getQueriesNode(siteName); 189 190 NodeIterator queryNodes = queriesNode.getNodes(); 191 while (queryNodes.hasNext()) 192 { 193 Node node = queryNodes.nextNode(); 194 195 // Extract a Query object from the node and add it to the map. 196 Query query = _extractQuery(node); 197 if (_matchQuery(query, dataSourceId, dataSourceType, resultType)) 198 { 199 queries.put(query.getId(), query); 200 } 201 } 202 203 return queries; 204 } 205 catch (RepositoryException e) 206 { 207 throw new DataInclusionException("Error getting the data sources", e); 208 } 209 } 210 211 private boolean _matchQuery (Query query, String dataSourceId, DataSourceType dsType, ResultType resultType) 212 { 213 if ((dataSourceId == null || query.getDataSourceId().equals(dataSourceId)) 214 && (dsType == null || query.getType().equals(dsType)) 215 && (resultType == null || resultType.equals(query.getResultType()))) 216 { 217 return true; 218 } 219 220 return false; 221 } 222 223 @Override 224 public Query getQuery(String siteName, String id) throws DataInclusionException 225 { 226 try 227 { 228 Query query = null; 229 230 Node queriesNode = _getQueriesNode(siteName); 231 232 if (queriesNode.hasNode(id)) 233 { 234 Node node = queriesNode.getNode(id); 235 236 // Extract a Query object from the node. 237 query = _extractQuery(node); 238 } 239 240 return query; 241 } 242 catch (RepositoryException e) 243 { 244 throw new DataInclusionException("Error getting the data source of id " + id, e); 245 } 246 } 247 248 @Override 249 @Callable 250 public Map<String, Object> getQueryProperties(String id, String siteName) throws DataInclusionException 251 { 252 Map<String, Object> infos = new HashMap<>(); 253 254 Query query = getQuery(siteName, id); 255 if (query != null) 256 { 257 infos.put("id", query.getId()); 258 infos.put("name", query.getName()); 259 infos.put("description", query.getDescription()); 260 infos.put("type", query.getType()); 261 infos.put("resultType", query.getResultType().name()); 262 263 Map<String, String> additionalConf = query.getAdditionalConfiguration(); 264 for (String confName : additionalConf.keySet()) 265 { 266 String value = additionalConf.get(confName); 267 if (value != null) 268 { 269 infos.put(confName, value); 270 } 271 } 272 273 infos.put("parameters", query.getParameters()); 274 275 infos.put("dataSourceId", query.getDataSourceId()); 276 } 277 278 return infos; 279 } 280 281 @Override 282 @Callable 283 public Map<String, String> addQuery(String siteName, Map<String, Object> parameters) throws Exception 284 { 285 Map<String, String> result = new HashMap<>(); 286 287 String type = (String) parameters.get("type"); 288 String name = (String) parameters.get("name"); 289 String description = (String) parameters.get("description"); 290 String resultTypeStr = (String) parameters.get("resultType"); 291 ResultType resultType = _getResultType(resultTypeStr, ResultType.MULTIPLE); 292 String dataSourceId = (String) parameters.get("dataSourceId"); 293 294 DataSourceFactory<Query, QueryResult> factory = _dataSourceFactoryEP.getFactory(DataSourceType.valueOf(type)); 295 if (factory == null) 296 { 297 getLogger().error("Impossible to get a factory to handle the type : " + type); 298 result.put("error", "unknown-type"); 299 return result; 300 } 301 Collection<String> params = factory.getQueryConfigurationParameters(type); 302 303 Map<String, String> additionalConfiguration = new HashMap<>(); 304 for (String paramName : params) 305 { 306 String value = (String) parameters.get(paramName); 307 if (value != null) 308 { 309 additionalConfiguration.put(paramName, value); 310 } 311 } 312 313 try 314 { 315 Query query = factory.buildQuery(null, type, name, description, resultType, dataSourceId, additionalConfiguration); 316 317 String id = addQuery(siteName, query); 318 319 if (getLogger().isDebugEnabled()) 320 { 321 getLogger().debug("Query created : got id " + id); 322 } 323 324 result.put("id", id); 325 result.put("parentId", dataSourceId); 326 result.put("type", type); 327 } 328 catch (DataInclusionException e) 329 { 330 getLogger().error("Error saving the query", e); 331 result.put("error", "add-query-error"); 332 } 333 334 return result; 335 } 336 337 @Override 338 public String addQuery(String siteName, Query query) throws DataInclusionException 339 { 340 try 341 { 342 Node queriesNode = _getQueriesNode(siteName); 343 344 String name = query.getName(); 345 if (StringUtils.isBlank(name)) 346 { 347 throw new DataInclusionException("Query name can't be blank."); 348 } 349 350 String nodeName = NameHelper.filterName(name); 351 String notExistingNodeName = _getNotExistingNodeName(queriesNode, nodeName); 352 353 // TODO Create a query JCR node type. 354 Node node = queriesNode.addNode(notExistingNodeName); 355 String id = node.getName(); 356 node.addMixin(JcrConstants.MIX_REFERENCEABLE); 357 358 _fillQueryNode(query, node); 359 360 queriesNode.getSession().save(); 361 362 return id; 363 } 364 catch (RepositoryException e) 365 { 366 throw new DataInclusionException("Error adding a Query", e); 367 } 368 } 369 370 @Override 371 @Callable 372 public Map<String, String> updateQuery(String siteName, Map<String, Object> parameters) throws Exception 373 { 374 Map<String, String> result = new HashMap<>(); 375 376 String id = (String) parameters.get("id"); 377 String type = (String) parameters.get("type"); 378 String name = (String) parameters.get("name"); 379 String description = (String) parameters.get("description"); 380 String resultTypeStr = (String) parameters.get("resultType"); 381 ResultType resultType = _getResultType(resultTypeStr, ResultType.MULTIPLE); 382 383 DataSourceFactory<Query, QueryResult> factory = _dataSourceFactoryEP.getFactory(DataSourceType.valueOf(type)); 384 Collection<String> params = factory.getQueryConfigurationParameters(type); 385 386 Map<String, String> additionalConfiguration = new HashMap<>(); 387 for (String paramName : params) 388 { 389 String value = (String) parameters.get(paramName); 390 if (value != null) 391 { 392 additionalConfiguration.put(paramName, value); 393 } 394 } 395 396 try 397 { 398 Query query = factory.buildQuery(id, type, name, description, resultType, null, additionalConfiguration); 399 400 updateQuery(siteName, query); 401 402 if (getLogger().isDebugEnabled()) 403 { 404 getLogger().debug("Query updated : id " + query.getId()); 405 } 406 407 Map<String, Object> eventParams = new HashMap<>(); 408 eventParams.put(ObservationConstants.ARGS_QUERY_ID, query.getId()); 409 _observationManager.notify(new Event(ObservationConstants.EVENT_QUERY_UPDATED, _currentUserProvider.getUser(), eventParams)); 410 411 result.put("id", id); 412 result.put("type", type); 413 } 414 catch (DataInclusionException e) 415 { 416 getLogger().error("Error updating the query", e); 417 result.put("error", "update-query-error"); 418 } 419 420 return result; 421 } 422 423 @Override 424 public void updateQuery(String siteName, Query query) throws DataInclusionException 425 { 426 String id = query.getId(); 427 428 try 429 { 430 Node queriesNode = _getQueriesNode(siteName); 431 432 if (!queriesNode.hasNode(id)) 433 { 434 throw new DataInclusionException("No query exists with id " + id); 435 } 436 437 Node node = queriesNode.getNode(id); 438 439 String name = query.getName(); 440 if (StringUtils.isBlank(name)) 441 { 442 throw new DataInclusionException("Name can't be blank."); 443 } 444 445 _fillQueryNode(query, node); 446 447 node.getSession().save(); 448 } 449 catch (RepositoryException e) 450 { 451 throw new DataInclusionException("Error updating the Data Source of id " + id, e); 452 } 453 } 454 455 @Override 456 @Callable 457 public Map<String, String> deleteQuery(String siteName, String id) throws Exception 458 { 459 Map<String, String> result = new HashMap<>(); 460 461 try 462 { 463 removeQuery(siteName, id); 464 465 if (getLogger().isDebugEnabled()) 466 { 467 getLogger().debug("Query id " + id + " deleted."); 468 } 469 470 Map<String, Object> eventParams = new HashMap<>(); 471 eventParams.put(ObservationConstants.ARGS_QUERY_ID, id); 472 _observationManager.notify(new Event(ObservationConstants.EVENT_QUERY_DELETED, _currentUserProvider.getUser(), eventParams)); 473 474 result.put("id", id); 475 } 476 catch (DataInclusionException e) 477 { 478 getLogger().error("Error deleting the query", e); 479 result.put("error", "delete-query-error"); 480 } 481 482 return result; 483 } 484 485 @Override 486 public void removeQuery(String siteName, String id) throws DataInclusionException 487 { 488 try 489 { 490 Node queriesNode = _getQueriesNode(siteName); 491 492 if (!queriesNode.hasNode(id)) 493 { 494 throw new DataInclusionException("No data source exists with id " + id); 495 } 496 497 queriesNode.getNode(id).remove(); 498 499 queriesNode.getSession().save(); 500 } 501 catch (RepositoryException e) 502 { 503 throw new DataInclusionException("Error updating the Data Source of id " + id, e); 504 } 505 } 506 507 /** 508 * Create a data source from a node. 509 * @param node the data source node. 510 * @return the data source. 511 * @throws RepositoryException if an error occurs when exploring the repository 512 * @throws DataInclusionException if an error occurs while manipulating the data sources 513 */ 514 protected Query _extractQuery(Node node) throws RepositoryException, DataInclusionException 515 { 516 Query query = null; 517 518 String id = node.getName(); 519 String type = _getSingleProperty(node, PROPERTY_TYPE, ""); 520 String name = _getSingleProperty(node, PROPERTY_NAME, ""); 521 String description = _getSingleProperty(node, PROPERTY_DESCRIPTION, ""); 522 ResultType resultType = _getResultType(node, ResultType.MULTIPLE); 523 String dataSourceId = _getSingleProperty(node, PROPERTY_DATASOURCE, ""); 524 Map<String, String> additionalConf = _getAdditionalConf(node); 525 526 DataSourceFactory<Query, QueryResult> factory = _dataSourceFactoryEP.getFactory(DataSourceType.valueOf(type)); 527 528 if (factory != null) 529 { 530 query = factory.buildQuery(id, type, name, description, resultType, dataSourceId, additionalConf); 531 } 532 else 533 { 534 throw new DataInclusionException("Unknown query type."); 535 } 536 537 return query; 538 } 539 540 /** 541 * Get a single property value. 542 * @param node the JCR node. 543 * @param propertyName the name of the property to get. 544 * @param defaultValue the default value if the property does not exist. 545 * @return the single property value. 546 * @throws RepositoryException if a repository error occurs. 547 */ 548 protected String _getSingleProperty(Node node, String propertyName, String defaultValue) throws RepositoryException 549 { 550 String value = defaultValue; 551 552 if (node.hasProperty(propertyName)) 553 { 554 value = node.getProperty(propertyName).getString(); 555 } 556 557 return value; 558 } 559 560 /** 561 * Get a a result type 562 * @param value the value 563 * @param defaultValue the default result type 564 * @return the result type for the value 565 * @throws RepositoryException if an error occurs when exploring the repository 566 */ 567 protected ResultType _getResultType(String value, ResultType defaultValue) throws RepositoryException 568 { 569 ResultType result = defaultValue; 570 try 571 { 572 result = ResultType.valueOf(value); 573 } 574 catch (Exception e) 575 { 576 // Ignore 577 } 578 579 return result; 580 } 581 582 /** 583 * Get a single property value. 584 * @param node the node 585 * @param defaultValue the default result type 586 * @return the result type for the value 587 * @throws RepositoryException if an error occurs when exploring the repository 588 */ 589 protected ResultType _getResultType(Node node, ResultType defaultValue) throws RepositoryException 590 { 591 ResultType result = defaultValue; 592 if (node.hasProperty(QUERY_PROPERTY_RESULTTYPE)) 593 { 594 String value = node.getProperty(QUERY_PROPERTY_RESULTTYPE).getString(); 595 try 596 { 597 result = ResultType.valueOf(value); 598 } 599 catch (Exception e) 600 { 601 // Ignore 602 } 603 } 604 605 return result; 606 } 607 608 /** 609 * Get the values of a string array property. 610 * @param node the node. 611 * @param propertyName the name of the property to get. 612 * @return the values. 613 * @throws RepositoryException if a repository error occurs. 614 */ 615 protected Collection<String> _getMultipleProperty(Node node, String propertyName) throws RepositoryException 616 { 617 List<String> values = new ArrayList<>(); 618 619 if (node.hasProperty(propertyName)) 620 { 621 Value[] propertyValues = node.getProperty(propertyName).getValues(); 622 for (Value value : propertyValues) 623 { 624 values.add(value.getString()); 625 } 626 } 627 628 return values; 629 } 630 631 /** 632 * Get additional configuration from properties. 633 * @param node the node 634 * @return the additional configuration as a Map. 635 * @throws RepositoryException if a repository error occurs. 636 */ 637 protected Map<String, String> _getAdditionalConf(Node node) throws RepositoryException 638 { 639 Map<String, String> values = new HashMap<>(); 640 641 PropertyIterator propertyIt = node.getProperties(PROPERTY_CONF_PREFIX + "*"); 642 while (propertyIt.hasNext()) 643 { 644 Property property = propertyIt.nextProperty(); 645 String propName = property.getName(); 646 String name = propName.substring(PROPERTY_CONF_PREFIX.length(), propName.length()); 647 String value = property.getString(); 648 649 values.put(name, value); 650 } 651 652 return values; 653 } 654 655 /** 656 * Store the query properties into the JCR node. 657 * @param query the querys 658 * @param node the query node 659 * @throws RepositoryException if a repository error occurs. 660 */ 661 protected void _fillQueryNode(Query query, Node node) throws RepositoryException 662 { 663 node.setProperty(PROPERTY_NAME, query.getName()); 664 node.setProperty(PROPERTY_DESCRIPTION, query.getDescription()); 665 node.setProperty(PROPERTY_TYPE, query.getType().name()); 666 node.setProperty(QUERY_PROPERTY_RESULTTYPE, query.getResultType().name()); 667 if (query.getDataSourceId() != null) 668 { 669 node.setProperty(PROPERTY_DATASOURCE, query.getDataSourceId()); 670 } 671 672 Map<String, String> additionalConf = query.getAdditionalConfiguration(); 673 for (String confName : additionalConf.keySet()) 674 { 675 String value = additionalConf.get(confName); 676 node.setProperty(PROPERTY_CONF_PREFIX + confName, value); 677 } 678 } 679 680 /** 681 * Get a name for a node which doesn't already exist in this node. 682 * @param container the container node. 683 * @param baseName the base wanted node name. 684 * @return the name, free to be taken. 685 * @throws RepositoryException if a repository error occurs. 686 */ 687 protected String _getNotExistingNodeName(Node container, String baseName) throws RepositoryException 688 { 689 String name = baseName; 690 691 int index = 2; 692 while (container.hasNode(name)) 693 { 694 name = baseName + index; 695 index++; 696 } 697 698 return name; 699 } 700 701 /** 702 * Get the plugin root node in a site storage space. 703 * @param siteName the site name. 704 * @return the plugin root node. 705 * @throws RepositoryException if a repository error occurs. 706 */ 707 protected Node _getPluginNode(String siteName) throws RepositoryException 708 { 709 710 Node pluginNode; 711 Session session = null; 712 try 713 { 714 session = _repository.login(); 715 ModifiableTraversableAmetysObject rootPlugins = _siteManager.getSite(siteName).getRootPlugins(); 716 Node pluginsNode = ((JCRAmetysObject) rootPlugins).getNode(); 717 718 if (pluginsNode.hasNode(PLUGIN_NODE)) 719 { 720 pluginNode = pluginsNode.getNode(PLUGIN_NODE); 721 } 722 else 723 { 724 pluginNode = pluginsNode.addNode(PLUGIN_NODE); 725 pluginsNode.getSession().save(); 726 } 727 728 return pluginNode; 729 } 730 catch (PathNotFoundException e) 731 { 732 if (session != null) 733 { 734 session.logout(); 735 } 736 737 throw new AmetysRepositoryException("Unable to get site plugins node for site " + siteName, e); 738 } 739 catch (RepositoryException e) 740 { 741 if (session != null) 742 { 743 session.logout(); 744 } 745 746 throw new AmetysRepositoryException("An error occured while getting site plugins node for site " + siteName, e); 747 } 748 } 749 750 /** 751 * Get the queries root node. 752 * @param siteName the name of the site 753 * @return the queries root node. 754 * @throws RepositoryException if a repository error occurs. 755 */ 756 protected Node _getQueriesNode(String siteName) throws RepositoryException 757 { 758 Node node; 759 try 760 { 761 Node pluginNode = _getPluginNode(siteName); 762 763 if (pluginNode.hasNode(QUERIES_NODE)) 764 { 765 node = pluginNode.getNode(QUERIES_NODE); 766 } 767 else 768 { 769 node = pluginNode.addNode(QUERIES_NODE); 770 pluginNode.getSession().save(); 771 } 772 773 return node; 774 } 775 catch (PathNotFoundException e) 776 { 777 throw new AmetysRepositoryException("Unable to get queries node because it doesn't exist.", e); 778 } 779 catch (RepositoryException e) 780 { 781 throw new AmetysRepositoryException("An error occured while getting queries node.", e); 782 } 783 } 784 785}