From 48b6974b076f086bce41889913a44a2932dfdee9 Mon Sep 17 00:00:00 2001 From: Beth Kirschner Date: Thu, 13 Feb 2014 20:02:28 +0000 Subject: [PATCH] INFRSTR-255 migrated from https://source.sakaiproject.org/contrib/hierarchy/ (see contrib repo for svn log history) git-svn-id: https://source.sakaiproject.org/svn/hierarchy/trunk@283600 66ffb92e-73f9-0310-93c1-f5514f145a0a --- hierarchy/.springBeans | 36 + hierarchy/.svnignore | 8 + hierarchy/LICENSE | 205 ++ hierarchy/NOTICE | 16 + hierarchy/README.txt | 5 + hierarchy/api/pom.xml | 43 + hierarchy/api/project.xml | 48 + .../hierarchy/HierarchyNodeReader.java | 82 + .../hierarchy/HierarchyNodeWriter.java | 114 ++ .../hierarchy/HierarchyPermissions.java | 128 ++ .../hierarchy/HierarchyProvider.java | 45 + .../hierarchy/HierarchyService.java | 57 + .../hierarchy/HierarchyTokens.java | 51 + .../dao/hbm/HierarchyNodeMetaData.hbm.xml | 29 + .../dao/hbm/HierarchyNodePermission.hbm.xml | 26 + .../dao/hbm/HierarchyPersistentNode.hbm.xml | 23 + .../dao/model/HierarchyNodeMetaData.java | 179 ++ .../dao/model/HierarchyNodePermission.java | 132 ++ .../dao/model/HierarchyPersistentNode.java | 130 ++ .../dao/oldhbm/HierarchyNodeMetaData.hbm.xml | 29 + .../oldhbm/HierarchyNodePermission.hbm.xml | 26 + .../oldhbm/HierarchyPersistentNode.hbm.xml | 23 + .../hierarchy/model/HierarchyNode.java | 140 ++ .../hierarchy/utils/HierarchyUtils.java | 110 ++ .../hierarchy/test/HierarchyUtilsTest.java | 90 + .../hierarchy/test/data/TestDataPreload.java | 71 + hierarchy/impl/pom.xml | 223 +++ hierarchy/impl/project.xml | 170 ++ hierarchy/impl/src/ddl/db2/hierarchy.sql | 41 + hierarchy/impl/src/ddl/derby/hierarchy.sql | 47 + .../impl/src/ddl/hibernate-db2.properties | 2 + .../impl/src/ddl/hibernate-derby.properties | 2 + .../impl/src/ddl/hibernate-hsqldb.properties | 2 + .../impl/src/ddl/hibernate-mssql.properties | 2 + .../impl/src/ddl/hibernate-mysql.properties | 2 + .../impl/src/ddl/hibernate-oracle.properties | 2 + .../src/ddl/hibernate-postgres.properties | 2 + hierarchy/impl/src/ddl/hibernate.cfg.xml | 13 + hierarchy/impl/src/ddl/hsqldb/hierarchy.sql | 41 + hierarchy/impl/src/ddl/mssql/hierarchy.sql | 41 + hierarchy/impl/src/ddl/mysql/hierarchy.sql | 41 + hierarchy/impl/src/ddl/oracle/hierarchy.sql | 47 + hierarchy/impl/src/ddl/pom.xml | 160 ++ hierarchy/impl/src/ddl/postgres/hierarchy.sql | 47 + .../hierarchy/dao/HierarchyDao.java | 36 + .../hierarchy/dao/HierarchyDaoImpl.java | 50 + .../hierarchy/dao/ResourceFinder.java | 92 + .../hierarchy/impl/HierarchyServiceImpl.java | 1138 ++++++++++++ .../impl/utils/HierarchyImplUtils.java | 187 ++ hierarchy/impl/src/test/hibernate-test.xml | 59 + hierarchy/impl/src/test/hibernate.properties | 17 + .../impl/test/HierarchyImplUtilsTest.java | 231 +++ .../impl/test/HierarchyServiceImplTest.java | 1645 +++++++++++++++++ .../impl/test/data/TestDataPreload.java | 233 +++ hierarchy/pack/pom.xml | 29 + hierarchy/pack/project.xml | 62 + .../pack/src/webapp/WEB-INF/components.xml | 18 + .../src/webapp/WEB-INF/sakai-hibernate.xml | 12 + .../src/webapp/WEB-INF/spring-hibernate.xml | 48 + hierarchy/pom.xml | 99 + hierarchy/project.properties | 1 + hierarchy/project.xml | 30 + 62 files changed, 6718 insertions(+) create mode 100644 hierarchy/.springBeans create mode 100644 hierarchy/.svnignore create mode 100644 hierarchy/LICENSE create mode 100644 hierarchy/NOTICE create mode 100644 hierarchy/README.txt create mode 100644 hierarchy/api/pom.xml create mode 100644 hierarchy/api/project.xml create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyNodeReader.java create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyNodeWriter.java create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyPermissions.java create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyProvider.java create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyService.java create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyTokens.java create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/hbm/HierarchyNodeMetaData.hbm.xml create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/hbm/HierarchyNodePermission.hbm.xml create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/hbm/HierarchyPersistentNode.hbm.xml create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/model/HierarchyNodeMetaData.java create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/model/HierarchyNodePermission.java create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/model/HierarchyPersistentNode.java create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/oldhbm/HierarchyNodeMetaData.hbm.xml create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/oldhbm/HierarchyNodePermission.hbm.xml create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/oldhbm/HierarchyPersistentNode.hbm.xml create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/model/HierarchyNode.java create mode 100644 hierarchy/api/src/java/org/sakaiproject/hierarchy/utils/HierarchyUtils.java create mode 100644 hierarchy/api/src/test/org/sakaiproject/hierarchy/test/HierarchyUtilsTest.java create mode 100644 hierarchy/api/src/test/org/sakaiproject/hierarchy/test/data/TestDataPreload.java create mode 100644 hierarchy/impl/pom.xml create mode 100644 hierarchy/impl/project.xml create mode 100644 hierarchy/impl/src/ddl/db2/hierarchy.sql create mode 100644 hierarchy/impl/src/ddl/derby/hierarchy.sql create mode 100644 hierarchy/impl/src/ddl/hibernate-db2.properties create mode 100644 hierarchy/impl/src/ddl/hibernate-derby.properties create mode 100644 hierarchy/impl/src/ddl/hibernate-hsqldb.properties create mode 100644 hierarchy/impl/src/ddl/hibernate-mssql.properties create mode 100644 hierarchy/impl/src/ddl/hibernate-mysql.properties create mode 100644 hierarchy/impl/src/ddl/hibernate-oracle.properties create mode 100644 hierarchy/impl/src/ddl/hibernate-postgres.properties create mode 100644 hierarchy/impl/src/ddl/hibernate.cfg.xml create mode 100644 hierarchy/impl/src/ddl/hsqldb/hierarchy.sql create mode 100644 hierarchy/impl/src/ddl/mssql/hierarchy.sql create mode 100644 hierarchy/impl/src/ddl/mysql/hierarchy.sql create mode 100644 hierarchy/impl/src/ddl/oracle/hierarchy.sql create mode 100644 hierarchy/impl/src/ddl/pom.xml create mode 100644 hierarchy/impl/src/ddl/postgres/hierarchy.sql create mode 100644 hierarchy/impl/src/java/org/sakaiproject/hierarchy/dao/HierarchyDao.java create mode 100644 hierarchy/impl/src/java/org/sakaiproject/hierarchy/dao/HierarchyDaoImpl.java create mode 100644 hierarchy/impl/src/java/org/sakaiproject/hierarchy/dao/ResourceFinder.java create mode 100644 hierarchy/impl/src/java/org/sakaiproject/hierarchy/impl/HierarchyServiceImpl.java create mode 100644 hierarchy/impl/src/java/org/sakaiproject/hierarchy/impl/utils/HierarchyImplUtils.java create mode 100644 hierarchy/impl/src/test/hibernate-test.xml create mode 100644 hierarchy/impl/src/test/hibernate.properties create mode 100644 hierarchy/impl/src/test/org/sakaiproject/hierarchy/impl/test/HierarchyImplUtilsTest.java create mode 100644 hierarchy/impl/src/test/org/sakaiproject/hierarchy/impl/test/HierarchyServiceImplTest.java create mode 100644 hierarchy/impl/src/test/org/sakaiproject/hierarchy/impl/test/data/TestDataPreload.java create mode 100644 hierarchy/pack/pom.xml create mode 100644 hierarchy/pack/project.xml create mode 100644 hierarchy/pack/src/webapp/WEB-INF/components.xml create mode 100644 hierarchy/pack/src/webapp/WEB-INF/sakai-hibernate.xml create mode 100644 hierarchy/pack/src/webapp/WEB-INF/spring-hibernate.xml create mode 100644 hierarchy/pom.xml create mode 100644 hierarchy/project.properties create mode 100644 hierarchy/project.xml diff --git a/hierarchy/.springBeans b/hierarchy/.springBeans new file mode 100644 index 000000000000..4b301993fd3b --- /dev/null +++ b/hierarchy/.springBeans @@ -0,0 +1,36 @@ + + + 1 + + + + + + + pack/src/webapp/WEB-INF/components.xml + pack/src/webapp/WEB-INF/spring-hibernate.xml + impl/src/test/hibernate-test.xml + pack/src/webapp/WEB-INF/sakai-hibernate.xml + + + + + true + false + + pack/src/webapp/WEB-INF/components.xml + pack/src/webapp/WEB-INF/sakai-hibernate.xml + pack/src/webapp/WEB-INF/spring-hibernate.xml + + + + + true + false + + impl/src/test/hibernate-test.xml + pack/src/webapp/WEB-INF/spring-hibernate.xml + + + + diff --git a/hierarchy/.svnignore b/hierarchy/.svnignore new file mode 100644 index 000000000000..61f8b5b115a6 --- /dev/null +++ b/hierarchy/.svnignore @@ -0,0 +1,8 @@ +target +bin +m2-target +.classpath +.idea +.iml +.project +.settings diff --git a/hierarchy/LICENSE b/hierarchy/LICENSE new file mode 100644 index 000000000000..8ba6bfa600c2 --- /dev/null +++ b/hierarchy/LICENSE @@ -0,0 +1,205 @@ +Educational Community License, Version 2.0 (ECL-2.0) + +Educational Community License + +Version 2.0, April 2007 + +http://www.osedu.org/licenses/ + +The Educational Community License version 2.0 ("ECL") consists of the Apache +2.0 license, modified to change the scope of the patent grant in section 3 to +be specific to the needs of the education communities using this license. The +original Apache 2.0 license can be found at: +http://www.apache.org/licenses/LICENSE-2.0 + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the +copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other +entities that control, are controlled by, or are under common control with +that entity. For the purposes of this definition, "control" means (i) the +power, direct or indirect, to cause the direction or management of such +entity, whether by contract or otherwise, or (ii) ownership of fifty percent +(50%) or more of the outstanding shares, or (iii) beneficial ownership of such +entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation source, and +configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object +code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice that is +included in or attached to the work (an example is provided in the Appendix +below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative +Works shall not include works that remain separable from, or merely link (or +bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original +version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor for +inclusion in the Work by the copyright owner or by an individual or Legal +Entity authorized to submit on behalf of the copyright owner. For the purposes +of this definition, "submitted" means any form of electronic, verbal, or +written communication sent to the Licensor or its representatives, including +but not limited to communication on electronic mailing lists, source code +control systems, and issue tracking systems that are managed by, or on behalf +of, the Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise designated +in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and +such Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such +Contributor that are necessarily infringed by their Contribution(s) alone or +by combination of their Contribution(s) with the Work to which such +Contribution(s) was submitted. If You institute patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging that +the Work or a Contribution incorporated within the Work constitutes direct or +contributory patent infringement, then any patent licenses granted to You +under this License for that Work shall terminate as of the date such +litigation is filed. Any patent license granted hereby with respect to +contributions by an individual employed by an institution or organization is +limited to patent claims where the individual that is the author of the Work +is also the inventor of the patent claims licensed, and where the organization +or institution has the right to grant such license under applicable grant and +research funding agreements. No other express or implied licenses are granted. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works +thereof in any medium, with or without modifications, and in Source or Object +form, provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and You must cause any modified files to carry prominent notices +stating that You changed the files; and You must retain, in the Source form of +any Derivative Works that You distribute, all copyright, patent, trademark, +and attribution notices from the Source form of the Work, excluding those +notices that do not pertain to any part of the Derivative Works; and If the +Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of +the following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents +of the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. You may add Your own copyright statement to Your +modifications and may provide additional or different license terms and +conditions for use, reproduction, or distribution of Your modifications, or +for any such Derivative Works as a whole, provided Your use, reproduction, and +distribution of the Work otherwise complies with the conditions stated in this +License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally +submitted for inclusion in the Work by You to the Licensor shall be under the +terms and conditions of this License, without any additional terms or +conditions. Notwithstanding the above, nothing herein shall supersede or +modify the terms of any separate license agreement you may have executed with +Licensor regarding such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides +the Work (and each Contributor provides its Contributions) on an "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You +are solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a result of +this License or out of the use or inability to use the Work (including but not +limited to damages for loss of goodwill, work stoppage, computer failure or +malfunction, or any and all other commercial damages or losses), even if such +Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. +However, in accepting such obligations, You may act only on Your own behalf +and on Your sole responsibility, not on behalf of any other Contributor, and +only if You agree to indemnify, defend, and hold each Contributor harmless for +any liability incurred by, or claims asserted against, such Contributor by +reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Educational Community License to your work + +To apply the Educational Community License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "[]" replaced with +your own identifying information. (Don't include the brackets!) The text +should be enclosed in the appropriate comment syntax for the file format. We +also recommend that a file or class name and description of purpose be +included on the same "printed page" as the copyright notice for easier +identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] Licensed under the Educational +Community License, Version 2.0 (the "License"); you may not use this file +except in compliance with the License. You may obtain a copy of the License at + +http://www.osedu.org/licenses/ECL-2.0 + + Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations under +the License. \ No newline at end of file diff --git a/hierarchy/NOTICE b/hierarchy/NOTICE new file mode 100644 index 000000000000..17e366adb8df --- /dev/null +++ b/hierarchy/NOTICE @@ -0,0 +1,16 @@ +Sakai Hierarchy Service +Copyright 2014, The Apereo Foundation +This project includes software developed by The Apereo Foundation. +http://www.apereo.org/ + +Licensed under the Educational Community License, Version 2.0 +(the "License"); you may not use this software except in compliance +with the License. You may obtain a copy of the License at: + +http://opensource.org/licenses/ecl2.txt + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/hierarchy/README.txt b/hierarchy/README.txt new file mode 100644 index 000000000000..2262c45eea82 --- /dev/null +++ b/hierarchy/README.txt @@ -0,0 +1,5 @@ +This is the Sakai hierarchy project +This is meant to provide a high-performance hierarchy inside Sakai +Permissions support will be provided via a capabilities-based permissions schema +questions to +Aaron Zeckoski (aaronz@vt.edu) or Antranig Basman (antranig@caret.cam.ac.uk) \ No newline at end of file diff --git a/hierarchy/api/pom.xml b/hierarchy/api/pom.xml new file mode 100644 index 000000000000..5288ce5450b3 --- /dev/null +++ b/hierarchy/api/pom.xml @@ -0,0 +1,43 @@ + + 4.0.0 + + + hierarchy + org.sakaiproject + 10.0-SNAPSHOT + + + Sakai Hierarchy API + org.sakaiproject.hierarchy + hierarchy-api + jar + + + shared + + + + + + + ${basedir}/src/java + + **/*.xml + + + + + ${basedir} + + *.txt + src/**/*.java + src/**/*.html + src/**/*.xml + src/**/*.properties + + false + + + + + \ No newline at end of file diff --git a/hierarchy/api/project.xml b/hierarchy/api/project.xml new file mode 100644 index 000000000000..7769f318efca --- /dev/null +++ b/hierarchy/api/project.xml @@ -0,0 +1,48 @@ + + + 3 + ../../master/project.xml + sakai-hierarchy-api + sakaiproject + sakai-hierarchy-api + ${sakai.version} + + CARET, Cambridge University + http://caret.cam.ac.uk/ + + 2007 + + + + jar + shared + + + + + + + sakaiproject + sakai + ${sakai.plugin.version} + plugin + + + + + + src/java + + + + ${basedir}/src/java + + **/*.xml + + + + + + + diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyNodeReader.java b/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyNodeReader.java new file mode 100644 index 000000000000..abdb2f6886df --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyNodeReader.java @@ -0,0 +1,82 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy; + +import java.util.Map; +import java.util.Set; + +import org.sakaiproject.hierarchy.model.HierarchyNode; + +/** + * Allows user to get hierarchical node data from the hierarchy + * + * @author Aaron Zeckoski (aaronz@vt.edu) + */ +public interface HierarchyNodeReader { + + /** + * Get the hierarchy root node for a specific hierarchy if it exists + * @param hierarchyId a unique string which identifies this hierarchy + * @return the {@link HierarchyNode} representing the root of the hierarchy + * if found, otherwise returns a null + */ + public HierarchyNode getRootNode(String hierarchyId); + + /** + * Get a node based on the unique id, + * convenience method for {@link #getNodesByIds(String[])} + * @param nodeId a unique id for a hierarchy node + * @return the {@link HierarchyNode} representing this node or null if it does not exist + */ + public HierarchyNode getNodeById(String nodeId); + + /** + * Get a set of nodes based on their unique ids, + * NOTE: this method is here for efficiency + * @param nodeIds unique ids for hierarchy nodes + * @return a map of nodeId -> {@link HierarchyNode} + */ + public Map getNodesByIds(String[] nodeIds); + + /** + * Get all the parent nodes for a specific node all the way to the root node, + * returns empty set if this is the root node + * + * @param nodeId a unique id for a hierarchy node + * @param directOnly if true then only include the nodes which are directly connected to this node, + * else return every node that is a parent of this node + * @return a Set of {@link HierarchyNode} objects representing all parent nodes for the specified child, + * empty set if no parents found + */ + public Set getParentNodes(String nodeId, boolean directOnly); + + /** + * Get all children nodes for this node in the hierarchy all the way to the leaves, + * will return no nodes if this node has no children + * + * @param nodeId a unique id for a hierarchy node + * @param directOnly if true then only include the nodes which are directly connected to this node, + * else return every node that is a child of this node + * @return a Set of {@link HierarchyNode} objects representing all children nodes for the specified parent, + * empty set if no children found + */ + public Set getChildNodes(String nodeId, boolean directOnly); + +} diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyNodeWriter.java b/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyNodeWriter.java new file mode 100644 index 000000000000..1cd3a2011aab --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyNodeWriter.java @@ -0,0 +1,114 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy; + +import org.sakaiproject.hierarchy.model.HierarchyNode; + +/** + * Allows user to control nodes (create, update, remove) + * + * @author Aaron Zeckoski (aaronz@vt.edu) + */ +public interface HierarchyNodeWriter { + + /** + * Add a new node to a hierarchy + * @param hierarchyId a unique id which defines the hierarchy + * @param parentNodeId the unique id for the parent of this node, can be null if this is the root or a top level node + * @return the object representing the newly added node + */ + public HierarchyNode addNode(String hierarchyId, String parentNodeId); + + /** + * Remove a node from the hierarchy if it is possible, + * nodes can only be removed if they have no children associations, + * root nodes can never be removed, + * exception occurs if these rules are violated + * @param nodeId a unique id for a hierarchy node + * @return the object representing the parent of the removed node + */ + public HierarchyNode removeNode(String nodeId); + + /** + * Add parents to a node (creates the association), + * only adds direct parents (directly connected to this node), + * others are implicitly defined,
+ * this will not create loops in the hierarchy + * @param nodeId a unique id for a hierarchy node + * @param parentNodeId a unique id for a hierarchy node which will be a parent of this node + * @return the object representing the updated node + */ + public HierarchyNode addParentRelation(String nodeId, String parentNodeId); + + /** + * Add children to a node (creates the association), + * only adds direct children (directly connected to this node), + * others are implicitly defined,
+ * this will not create loops in the hierarchy + * @param nodeId a unique id for a hierarchy node + * @param childNodeId a unique id for a hierarchy node which will be a child of this node + * @return the object representing the updated node + */ + public HierarchyNode addChildRelation(String nodeId, String childNodeId); + + /** + * Remove a parent relation from a node, + * this will not be allowed to orphan a node, + * only extra parents may be removed, + * the last parent for a node cannot currently be removed + * @param nodeId a unique id for a hierarchy node + * @param parentNodeId a unique id for a hierarchy node which is a parent of this node + * @return the object representing the updated node + */ + public HierarchyNode removeParentRelation(String nodeId, String parentNodeId); + + /** + * Remove a child relation from a node, + * this will not be allowed to orphan a node + * @param nodeId a unique id for a hierarchy node + * @param childNodeId a unique id for a hierarchy node which is a child of this node + * @return the object representing the updated node + */ + public HierarchyNode removeChildRelation(String nodeId, String childNodeId); + + + /** + * Save meta data on a node, this is optional and nodes do not need meta data associated, + * if the params are nulls then the values remain unchanged, if they are empty string + * then the values are wiped out + * @param nodeId a unique id for a hierarchy node + * @param title the title of the node (optional) + * @param description a description for this node (optional) + * @param permKey the permission token key associated with this node (optional) + * @return the object representing the updated node + */ + public HierarchyNode saveNodeMetaData(String nodeId, String title, String description, String permKey); + + /** + * Enables/disables the node. This is used when a user updates the hierarchy but wishes to + * retain any links to the node until they can be properly updated as well. + * + * @param nodeId a unique id for a hierarchy node + * @param isDisabled Boolean representing the state the node will be set to + * @return the object representing the updated node + */ + public HierarchyNode setNodeDisabled(String nodeId, Boolean isDisabled); + +} diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyPermissions.java b/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyPermissions.java new file mode 100644 index 000000000000..1249e1566519 --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyPermissions.java @@ -0,0 +1,128 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy; + +import java.util.Map; +import java.util.Set; + +import org.sakaiproject.hierarchy.model.HierarchyNode; + +/** + * This interface contains the methods for assigning and checking permissions in the hierarchy + * + * @author Aaron Zeckoski (azeckoski @ gmail.com) + */ +public interface HierarchyPermissions { + + /** + * Determine if a user has a specific hierarchy permission at a specific hierarchy node, + * a permission key can be any string though it will most likely be from a relatively small set + * + * @param userId the internal user id (not username) + * @param nodeId a unique id for a hierarchy node + * @param hierarchyPermission a string which indicates a permission key (e.g. delete.item) + * @return true if the user has this permission, false otherwise + */ + public boolean checkUserNodePerm(String userId, String nodeId, String hierarchyPermission); + + // ASSIGN + + /** + * Assign the given permission to a user for the given hierarchy node, + * can cascade the permission downward if desired + * + * @param userId the internal user id (not username) + * @param nodeId a unique id for a hierarchy node + * @param hierarchyPermission a string which indicates a permission key (e.g. delete.item) + * @param cascade if true then the permission is assigned to all nodes below this one as well, + * if false it is only assigned to this node + */ + public void assignUserNodePerm(String userId, String nodeId, String hierarchyPermission, boolean cascade); + + /** + * Remove a permission for a user from the given hierarchy node, + * can cascade the permission downward if desired + * + * @param userId the internal user id (not username) + * @param nodeId a unique id for a hierarchy node + * @param hierarchyPermission a string which indicates a permission key (e.g. delete.item) + * @param cascade if true then the permission is removed from all nodes below this one as well, + * if false it is only removed from this node + */ + public void removeUserNodePerm(String userId, String nodeId, String hierarchyPermission, boolean cascade); + + // NODES + + /** + * Get all the userIds for users which have a specific permission in a set of + * hierarchy nodes, this can be used to check one node or many nodes as needed + * + * @param nodeIds an array of unique ids for hierarchy nodes + * @param hierarchyPermission a string which indicates a permission key (e.g. delete.item) + * @return a set of userIds (not username/eid) + */ + public Set getUserIdsForNodesPerm(String[] nodeIds, String hierarchyPermission); + + /** + * Get the hierarchy nodes which a user has a specific permission in, + * this is used to find a set of nodes which a user should be able to see and to build + * the list of hierarchy nodes a user has a given permission in + * + * @param userId the internal user id (not username) + * @param hierarchyPermission a string which indicates a permission key (e.g. delete.item) + * @return a Set of {@link HierarchyNode} objects + */ + public Set getNodesForUserPerm(String userId, String hierarchyPermission); + + /** + * Get the set of all permissions which a user has on a node or group of nodes, + * NOTE: this will get the set of ALL permissions inclusively for the given nodeIds + * so nodes in the set which a user has no permissions on will not cause this to return no permissions, + * example: for given user: nodeA(perm1, perm2), nodeB(perm1), nodeC(perm2), nodeD() : returns: (perm1, perm2) + * + * @param userId the internal user id (not username) + * @param nodeIds an array of unique ids for hierarchy nodes + * @return the set of permission keys which exist on any of the given nodes + */ + public Set getPermsForUserNodes(String userId, String[] nodeIds); + + /** + * Get all the users and permissions currently assigned to nodes, + * the returned map will always contain every passed in nodeId as a key + *
+ * This is not super efficient by itself so it should not used when other methods are sufficient, + * however, it is actually much better than calling the other methods repeatedly so this is primarily + * for use in administrative interfaces + * + * @param nodeIds an array of unique ids for hierarchy nodes + * @return the map of nodeId -> (map of userId -> Set(permission)) + */ + public Map>> getUsersAndPermsForNodes(String... nodeIds); + + /** + * Get all the nodeIds and permissions for the given userIds, + * the returned map will always contain every userId that was passed in as a key + * + * @param userIds an array of unique ids for users (internal id, not eid) + * @return the map of userId -> (map of nodeId -> Set(permission)) + */ + public Map>> getNodesAndPermsForUser(String... userIds); + +} diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyProvider.java b/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyProvider.java new file mode 100644 index 000000000000..7baeced172d5 --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyProvider.java @@ -0,0 +1,45 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy; + +/** + * This interface provides methods to get hierarchical node data into sakai + * for use in determining the structure above sites/groups related to + * adminstration and access to data and control of permissions + * + * @author Aaron Zeckoski (aaronz@vt.edu) + */ +public interface HierarchyProvider extends HierarchyNodeReader { + + public static final String HIERARCHY_PERM_NODE_UPDATE = "perm_node_update"; + public static final String HIERARCHY_PERM_NODE_REMOVE = "perm_node_remove"; + + /** + * Determine if a user has a specific hierarchy permission at a specific hierarchy node + *
The actual permissions this should handle are shown at the top of this class + * + * @param userId the internal user id (not username) + * @param nodeId a unique id for a hierarchy node + * @param hierarchyPermConstant a HIERARCHY_PERM_NODE constant + * @return true if the user has this permission, false otherwise + */ + public boolean checkUserNodePerm(String userId, String nodeId, String hierarchyPermConstant); + +} diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyService.java b/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyService.java new file mode 100644 index 000000000000..fe7ae07af948 --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyService.java @@ -0,0 +1,57 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy; + +import org.sakaiproject.hierarchy.model.HierarchyNode; + + +/** + * This service interface defines the capabilities of the hierarchy system + * + * @author Aaron Zeckoski (aaronz@vt.edu) + */ +public interface HierarchyService extends HierarchyNodeReader, HierarchyNodeWriter, HierarchyTokens, HierarchyPermissions { + + /** + * Creates a new hierarchy with the unique id specified, exception if this id is already used + * @param hierarchyId a unique id which defines the hierarchy + * @return the object representing the root node of the new hierarchy + */ + public HierarchyNode createHierarchy(String hierarchyId); + + /** + * Sets the root node of this hierarchy, note that although a hierarchy might have multiple + * nodes at the top of the hierarchy, it always has a primary node which is considering the + * "entry point" into the hierarchy
+ * A node must have no parents to be set to the root node
+ * The first node added to a hierarchy becomes the root node by default + * @param hierarchyId a unique id which defines the hierarchy + * @param nodeId a unique id for a hierarchy node + * @return the object representing the node which is now the root node + */ + public HierarchyNode setHierarchyRootNode(String hierarchyId, String nodeId); + + /** + * Completely and permanantly destroy a hierarchy and all related nodes + * @param hierarchyId a unique id which defines the hierarchy + */ + public void destroyHierarchy(String hierarchyId); + +} diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyTokens.java b/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyTokens.java new file mode 100644 index 000000000000..3b45e6289934 --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/HierarchyTokens.java @@ -0,0 +1,51 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy; + +import java.util.Map; +import java.util.Set; + + +/** + * This adds in the ability to define permissions key token searching + * + * @author Aaron Zeckoski (aaron@caret.cam.ac.uk) + */ +public interface HierarchyTokens { + + /** + * Find all nodes for a hierarchy associated with a token key + * + * @param hierarchyId a unique id which defines the hierarchy + * @param permToken a permissions token key + * @return a set of nodeIds, empty if no nodes found + */ + public Set getNodesWithToken(String hierarchyId, String permToken); + + /** + * Find all the nodes for a hierarchy associated with a set of token keys + * + * @param hierarchyId a unique id which defines the hierarchy + * @param permTokens an array of permissions token keys + * @return a map of tokenKey -> set of nodeIds, empty if no nodes found + */ + public Map> getNodesWithTokens(String hierarchyId, String[] permTokens); + +} diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/hbm/HierarchyNodeMetaData.hbm.xml b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/hbm/HierarchyNodeMetaData.hbm.xml new file mode 100644 index 000000000000..3a3956c07b51 --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/hbm/HierarchyNodeMetaData.hbm.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + HIERARCHY_META_ID_SEQ + + + + + + + + + + + + diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/hbm/HierarchyNodePermission.hbm.xml b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/hbm/HierarchyNodePermission.hbm.xml new file mode 100644 index 000000000000..52c83565e5c1 --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/hbm/HierarchyNodePermission.hbm.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + HIERARCHY_PERM_ID_SEQ + + + + + + + + + diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/hbm/HierarchyPersistentNode.hbm.xml b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/hbm/HierarchyPersistentNode.hbm.xml new file mode 100644 index 000000000000..cdbff814a81e --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/hbm/HierarchyPersistentNode.hbm.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + HIERARCHY_NODE_ID_SEQ + + + + + + + + diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/model/HierarchyNodeMetaData.java b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/model/HierarchyNodeMetaData.java new file mode 100644 index 000000000000..2027d1535208 --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/model/HierarchyNodeMetaData.java @@ -0,0 +1,179 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy.dao.model; + +/** + * This is the persistent object for storing Hierarchy Node meta data + * + * @author Aaron Zeckoski (aaronz@vt.edu) + */ +public class HierarchyNodeMetaData { + + /** + * The unique internal id for this meta data + */ + private Long id; + + /** + * this is the node that this meta data is associated with + */ + private HierarchyPersistentNode node; + + /** + * The assigned unique id for this hierarchy (used for lookup) + */ + private String hierarchyId; + + /** + * true if this is the rootnode for this hierarchy + */ + private Boolean isRootNode; + + /** + * the userId of the owner (creator) of the associated node + */ + private String ownerId; + + /** + * the title for the associated node + */ + private String title; + + /** + * the description for the associated node + */ + private String description; + + /** + * the permissions token for the associated node + */ + private String permToken; + + /** + * true if this node is disabled, i.e. left in hierarchy for historical purposes (default is false) + */ + private Boolean isDisabled; + + /** + * Empty constructor + */ + public HierarchyNodeMetaData() { + } + + /** + * minimal + */ + public HierarchyNodeMetaData(HierarchyPersistentNode node, String hierarchyId, Boolean isRootNode, + String ownerId) { + this.node = node; + this.hierarchyId = hierarchyId; + this.isRootNode = isRootNode; + this.ownerId = ownerId; + this.isDisabled = false; // default is false and needs to be set + } + + /** + * full + */ + public HierarchyNodeMetaData(HierarchyPersistentNode node, String hierarchyId, Boolean isRootNode, + String ownerId, String title, String description, String permToken, Boolean isDisabled) { + this.node = node; + this.hierarchyId = hierarchyId; + this.isRootNode = isRootNode; + this.ownerId = ownerId; + this.title = title; + this.description = description; + this.permToken = permToken; + this.isDisabled = isDisabled; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getHierarchyId() { + return hierarchyId; + } + + public void setHierarchyId(String hierarchyId) { + this.hierarchyId = hierarchyId; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Boolean getIsRootNode() { + return isRootNode; + } + + public void setIsRootNode(Boolean isRootNode) { + this.isRootNode = isRootNode; + } + + public HierarchyPersistentNode getNode() { + return node; + } + + public void setNode(HierarchyPersistentNode node) { + this.node = node; + } + + public String getOwnerId() { + return ownerId; + } + + public void setOwnerId(String ownerId) { + this.ownerId = ownerId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getPermToken() { + return permToken; + } + + public void setPermToken(String permToken) { + this.permToken = permToken; + } + + public Boolean getIsDisabled() { + return isDisabled; + } + + public void setIsDisabled(Boolean isDisabled) { + this.isDisabled = isDisabled; + } + +} diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/model/HierarchyNodePermission.java b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/model/HierarchyNodePermission.java new file mode 100644 index 000000000000..06d00ee0fb86 --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/model/HierarchyNodePermission.java @@ -0,0 +1,132 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy.dao.model; + +import java.io.Serializable; +import java.util.Date; + +/** + * This represents a single authorization entry in the hierarchy system, + * this is DROP dead simplistic and needs to probably be improved VASTLY + * + * @author Aaron Zeckoski (azeckoski @ gmail.com) + */ +public class HierarchyNodePermission implements Serializable { + private static final long serialVersionUID = 1L; + + private Long id; + private Date createdOn; + private Date lastModified; + private String userId; + private String nodeId; + private String permission; + + public HierarchyNodePermission() {} // default constructor needed for reflection + + public HierarchyNodePermission(String userId, String nodeId, String permission) { + if (userId == null || "".equals(userId) + || nodeId == null || "".equals(nodeId) + || permission == null || "".equals(permission)) { + throw new IllegalArgumentException("None of the inputs can be null or blank: type=" + userId + ":id=" + nodeId + ":eid=" + permission); + } + this.userId = userId; + this.nodeId = nodeId; + this.permission = permission; + this.id = null; // default to null + this.createdOn = new Date(); + this.lastModified = this.createdOn; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Date getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(Date createdOn) { + this.createdOn = createdOn; + } + + public Date getLastModified() { + return lastModified; + } + + public void setLastModified(Date lastModified) { + this.lastModified = lastModified; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getNodeId() { + return nodeId; + } + + public void setNodeId(String nodeId) { + this.nodeId = nodeId; + } + + public String getPermission() { + return permission; + } + + public void setPermission(String permission) { + this.permission = permission; + } + + @Override + public boolean equals(Object obj) { + if (null == obj) + return false; + if (!(obj instanceof HierarchyNodePermission)) + return false; + else { + HierarchyNodePermission castObj = (HierarchyNodePermission) obj; + boolean eq = (this.id == null ? castObj.id == null : this.id.equals(castObj.id)) + && (this.userId == null ? false : this.userId.equals(castObj.userId)) + && (this.nodeId == null ? false : this.nodeId.equals(castObj.nodeId)) + && (this.permission == null ? false : this.permission.equals(castObj.permission)); + return eq; + } + } + + @Override + public int hashCode() { + String hashStr = this.getClass().getName() + ":" + this.id + ":" + this.userId + ":" + this.permission + ":" + this.nodeId; + return hashStr.hashCode(); + } + + @Override + public String toString() { + return "idEid("+this.id+"):user="+this.userId+":perm="+this.permission+":ref="+this.nodeId; //+": "+super.toString(); + } + +} diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/model/HierarchyPersistentNode.java b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/model/HierarchyPersistentNode.java new file mode 100644 index 000000000000..6ccee846f709 --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/model/HierarchyPersistentNode.java @@ -0,0 +1,130 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy.dao.model; + +/** + * This is the persistent object for storing Hierarchy Nodes + * + * @author Aaron Zeckoski (aaronz@vt.edu) + */ +public class HierarchyPersistentNode { + + /** + * The unique internal id for this hierarchy node + */ + private Long id; + /** + * the ids of parent nodes that touch this node directly, + * similar treatment to the way the it works for the {@link #parentIds} + */ + private String directParentIds; + /** + * the ids of all parents of this node, + * this goes all the way up the hierarchy to the root node, + * expect this to be only one parent in most cases, + * the path to the root is determined using the directParentId only
+ * Uses a ":" separator between each id, also includes the separator in front + * of and behind every id.
+ * Examples: ":123:432:43:", ":38:", "" (no parent) + */ + private String parentIds; + /** + * the ids of child nodes that touch this node directly, + * similar treatment to the way the it works for the {@link #parentIds} + */ + private String directChildIds; + /** + * the ids of all children of this node, + * this goes all the way down the hierarchy to the leaf nodes, + * similar treatment to the way the it works for the {@link #parentIds} + */ + private String childIds; + + + /** + * Empty constructor + */ + public HierarchyPersistentNode() { + } + + /** + * Leaf constructor + */ + public HierarchyPersistentNode(String directParentIds, String parentIds) { + this.directParentIds = directParentIds; + this.parentIds = parentIds; + } + + /** + * Full constructor + */ + public HierarchyPersistentNode(String directParentIds, String parentIds, String directChildIds, String childIds) { + this.directParentIds = directParentIds; + this.directChildIds = directChildIds; + this.parentIds = parentIds; + this.childIds = childIds; + } + + + /** + * Getters and Setters + */ + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getParentIds() { + return parentIds; + } + + public void setParentIds(String parentIds) { + this.parentIds = parentIds; + } + + public String getDirectChildIds() { + return directChildIds; + } + + public void setDirectChildIds(String directChildIds) { + this.directChildIds = directChildIds; + } + + public String getDirectParentIds() { + return directParentIds; + } + + public void setDirectParentIds(String directParentIds) { + this.directParentIds = directParentIds; + } + + public String getChildIds() { + return childIds; + } + + public void setChildIds(String childIds) { + this.childIds = childIds; + } + +} diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/oldhbm/HierarchyNodeMetaData.hbm.xml b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/oldhbm/HierarchyNodeMetaData.hbm.xml new file mode 100644 index 000000000000..6d7090fb2dd0 --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/oldhbm/HierarchyNodeMetaData.hbm.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + HIERARCHY_META_ID_SEQ + + + + + + + + + + + + diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/oldhbm/HierarchyNodePermission.hbm.xml b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/oldhbm/HierarchyNodePermission.hbm.xml new file mode 100644 index 000000000000..68980edd5546 --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/oldhbm/HierarchyNodePermission.hbm.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + HIERARCHY_PERM_ID_SEQ + + + + + + + + + diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/oldhbm/HierarchyPersistentNode.hbm.xml b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/oldhbm/HierarchyPersistentNode.hbm.xml new file mode 100644 index 000000000000..09e7233a5444 --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/dao/oldhbm/HierarchyPersistentNode.hbm.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + HIERARCHY_NODE_ID_SEQ + + + + + + + + diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/model/HierarchyNode.java b/hierarchy/api/src/java/org/sakaiproject/hierarchy/model/HierarchyNode.java new file mode 100644 index 000000000000..86f1518d15be --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/model/HierarchyNode.java @@ -0,0 +1,140 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy.model; + +import java.util.Set; + +/** + * This pea represents a node in a hierarchy + * (in academics a department or college would probably be represented by a node) + * + * @author Aaron Zeckoski (aaronz@vt.edu) + */ +public class HierarchyNode { + + /** + * The unique id for this hierarchy node + */ + public String id; + /** + * The assigned unique id for the hierarchy this node is in + */ + public String hierarchyId; + /** + * the title of this node + */ + public String title; + /** + * the description for this node + */ + public String description; + /** + * the permissions token for the associated node, + * can be looked up in the permissions token key generator service + */ + public String permToken; + /** + * a set of all direct parents for this node, + * the ids of parent nodes that touch this node directly + */ + public Set directParentNodeIds; + /** + * a set of all direct children for this node, + * the ids of child nodes that touch this node directly + */ + public Set directChildNodeIds; + /** + * a set of all parents for this node + */ + public Set parentNodeIds; + /** + * a set of all children for this node + */ + public Set childNodeIds; + + /** + * boolean representing whether or not node is disabled + */ + public Boolean isDisabled; + + /** + * Empty constructor + */ + public HierarchyNode() {} + + /** + * Testing constructor + * @param id + * @param hierarchyId + * @param title + * @param permToken + * @param directParentNodeIds + * @param directChildNodeIds + * @param parentNodeIds + * @param childNodeIds + * @param isDisabled + */ + public HierarchyNode(String id, String hierarchyId, String title, + String permToken, Set directParentNodeIds, + Set parentNodeIds, Set directChildNodeIds, + Set childNodeIds, Boolean isDisabled) { + this.id = id; + this.hierarchyId = hierarchyId; + this.title = title; + this.permToken = permToken; + this.directParentNodeIds = directParentNodeIds; + this.parentNodeIds = parentNodeIds; + this.directChildNodeIds = directChildNodeIds; + this.childNodeIds = childNodeIds; + this.isDisabled = isDisabled; + } + + + /* + * overrides for various internal methods + */ + + @Override + public boolean equals(Object obj) { + if (null == obj) return false; + if (!(obj instanceof HierarchyNode)) return false; + else { + HierarchyNode castObj = (HierarchyNode) obj; + if (null == this.id || null == castObj.id) return false; + else return ( + this.id.equals(castObj.id) && + this.hierarchyId.equals(castObj.hierarchyId) + ); + } + } + + @Override + public int hashCode() { + if (null == this.id) return super.hashCode(); + String hashStr = this.getClass().getName() + ":" + this.id.hashCode() + ":" + this.hierarchyId.hashCode(); + return hashStr.hashCode(); + } + + @Override + public String toString() { + return "id:" + this.id + ";hierachyId:" + this.hierarchyId + ";parents:" + this.parentNodeIds.size() + ";children:" + this.childNodeIds.size(); + } + +} diff --git a/hierarchy/api/src/java/org/sakaiproject/hierarchy/utils/HierarchyUtils.java b/hierarchy/api/src/java/org/sakaiproject/hierarchy/utils/HierarchyUtils.java new file mode 100644 index 000000000000..15c05ff01b87 --- /dev/null +++ b/hierarchy/api/src/java/org/sakaiproject/hierarchy/utils/HierarchyUtils.java @@ -0,0 +1,110 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy.utils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.sakaiproject.hierarchy.model.HierarchyNode; + + +/** + * Simple utils to assist with working with the hierarchy + * + * @author Aaron Zeckoski (aaron@caret.cam.ac.uk) + */ +public class HierarchyUtils { + + /** + * Create a sorted list of nodes based on a set of input nodes, + * list goes from root (or highest parent) down to the bottom most node + * @param nodes + * @return a list of {@link HierarchyNode} + */ + public static List getSortedNodes(Collection nodes) { + List sortedNodes = new ArrayList(); + for (HierarchyNode hierarchyNode : nodes) { + if (sortedNodes.size() < 1) { + sortedNodes.add(hierarchyNode); + } else { + int i; + for (i = 0; i < sortedNodes.size(); i++) { + HierarchyNode sortedNode = sortedNodes.get(i); + if (sortedNode.parentNodeIds.contains(hierarchyNode.id)) { + break; + } + } + sortedNodes.add(i, hierarchyNode); + } + } + return sortedNodes; + } + + /** + * Create a set of all the unique child node ids based on the set of supplied nodes, + * can optionally be limited to return only direct children and to include the supplied node ids + * @param nodes a collection of {@link HierarchyNode} + * @param includeSuppliedNodes includes the nodeIds of the supplied collection of nodes in the returned set + * @param directOnly only use the direct children of each node + * @return the set of all unique child node ids + */ + public static Set getUniqueChildNodes(Collection nodes, boolean includeSuppliedNodeIds, boolean directOnly) { + Set s = new HashSet(); + for (HierarchyNode hierarchyNode : nodes) { + if (includeSuppliedNodeIds) { + s.add(hierarchyNode.id); + } + if (directOnly) { + s.addAll(hierarchyNode.directChildNodeIds); + } else { + s.addAll(hierarchyNode.childNodeIds); + } + } + return s; + } + + /** + * Create a set of all the unique parent node ids based on the set of supplied nodes, + * can optionally be limited to return only direct parents and to include the supplied node ids + * @param nodes a collection of {@link HierarchyNode} + * @param includeSuppliedNodes includes the nodeIds of the supplied collection of nodes in the returned set + * @param directOnly only use the direct parents of each node + * @return the set of all unique parent node ids + */ + public static Set getUniqueParentNodes(Collection nodes, boolean includeSuppliedNodeIds, boolean directOnly) { + Set s = new HashSet(); + for (HierarchyNode hierarchyNode : nodes) { + if (includeSuppliedNodeIds) { + s.add(hierarchyNode.id); + } + if (directOnly) { + s.addAll(hierarchyNode.directParentNodeIds); + } else { + s.addAll(hierarchyNode.parentNodeIds); + } + } + return s; + } + +} + diff --git a/hierarchy/api/src/test/org/sakaiproject/hierarchy/test/HierarchyUtilsTest.java b/hierarchy/api/src/test/org/sakaiproject/hierarchy/test/HierarchyUtilsTest.java new file mode 100644 index 000000000000..c22188f00f1d --- /dev/null +++ b/hierarchy/api/src/test/org/sakaiproject/hierarchy/test/HierarchyUtilsTest.java @@ -0,0 +1,90 @@ +/** + * HierarchyUtilsTest.java - hierarchy - 2007 Sep 11, 2007 2:10:03 PM - azeckoski + */ + +package org.sakaiproject.hierarchy.test; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.sakaiproject.hierarchy.model.HierarchyNode; +import org.sakaiproject.hierarchy.test.data.TestDataPreload; +import org.sakaiproject.hierarchy.utils.HierarchyUtils; + +import junit.framework.TestCase; + + +/** + * testing the static utils + * + * @author Aaron Zeckoski (aaron@caret.cam.ac.uk) + */ +public class HierarchyUtilsTest extends TestCase { + + private TestDataPreload tdp; + + /* (non-Javadoc) + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + tdp = new TestDataPreload(); + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.utils.HierarchyUtils#getSortedNodes(java.util.Collection)}. + */ + public void testGetSortedNodes() { + List l = null; + Set nodes = new HashSet(); + + nodes.clear(); + nodes.add(tdp.node7); + nodes.add(tdp.node4); + nodes.add(tdp.node1); + l = HierarchyUtils.getSortedNodes(nodes); + assertNotNull(l); + assertEquals(3, l.size()); + assertEquals(tdp.node1, l.get(0)); + assertEquals(tdp.node4, l.get(1)); + assertEquals(tdp.node7, l.get(2)); + + nodes.clear(); + nodes.add(tdp.node4); + nodes.add(tdp.node8); + nodes.add(tdp.node1); + l = HierarchyUtils.getSortedNodes(nodes); + assertNotNull(l); + assertEquals(3, l.size()); + assertEquals(tdp.node1, l.get(0)); + assertEquals(tdp.node4, l.get(1)); + assertEquals(tdp.node8, l.get(2)); + + nodes.clear(); + nodes.add(tdp.node1); + nodes.add(tdp.node3); + nodes.add(tdp.node5); + l = HierarchyUtils.getSortedNodes(nodes); + assertNotNull(l); + assertEquals(3, l.size()); + assertEquals(tdp.node1, l.get(0)); + assertEquals(tdp.node3, l.get(1)); + assertEquals(tdp.node5, l.get(2)); + + nodes.clear(); + nodes.add(tdp.node2); + nodes.add(tdp.node1); + l = HierarchyUtils.getSortedNodes(nodes); + assertNotNull(l); + assertEquals(2, l.size()); + assertEquals(tdp.node1, l.get(0)); + assertEquals(tdp.node2, l.get(1)); + + nodes.clear(); + l = HierarchyUtils.getSortedNodes(nodes); + assertNotNull(l); + assertEquals(0, l.size()); + + } + +} diff --git a/hierarchy/api/src/test/org/sakaiproject/hierarchy/test/data/TestDataPreload.java b/hierarchy/api/src/test/org/sakaiproject/hierarchy/test/data/TestDataPreload.java new file mode 100644 index 000000000000..4426cd7f1b44 --- /dev/null +++ b/hierarchy/api/src/test/org/sakaiproject/hierarchy/test/data/TestDataPreload.java @@ -0,0 +1,71 @@ +/****************************************************************************** + * TestDataPreload.java - created by Sakai App Builder -AZ + * + * Copyright (c) 2006 Sakai Project/Sakai Foundation + * Licensed under the Educational Community License version 1.0 + * + * A copy of the Educational Community License has been included in this + * distribution and is available at: http://www.opensource.org/licenses/ecl1.php + * + *****************************************************************************/ + +package org.sakaiproject.hierarchy.test.data; + +import java.util.Set; +import java.util.TreeSet; + +import org.sakaiproject.hierarchy.model.HierarchyNode; + +/** + * Contains test data for preloading and test constants + * @author Aaron Zeckoski (aaronz@vt.edu) + */ +public class TestDataPreload { + + /** + * this permission does not translate + */ + public final static String PERM_TOKEN_1 = "tokenKey1"; + /** + * this permission should translate downward + */ + public final static String PERM_TOKEN_2 = "tokenKey2"; + public final static String INVALID_PERM_TOKEN = "invalid-permtoken"; + + // testing constants + public final static String HIERARCHYA = "hierarchyA"; + public final static String HIERARCHYB = "hierarchyB"; + public final static String INVALID_HIERARCHY = "hierarchy-invalid"; + public final static String INVALID_NODE_ID = "invalid-nodeID"; + + // testing data objects here + public HierarchyNode node1 = new HierarchyNode("1", HIERARCHYA, "Univ of AZ", null, toSet(""), toSet(""), toSet("2,3,4"), toSet("2,3,4,5,6,7,8"), Boolean.FALSE ); + public HierarchyNode node2 = new HierarchyNode("2", HIERARCHYA, "College of Engineering", PERM_TOKEN_1, toSet("1"), toSet("1"), toSet(""), toSet(""), Boolean.FALSE ); + public HierarchyNode node3 = new HierarchyNode("3", HIERARCHYA, "College of Arts", PERM_TOKEN_1, toSet("1"), toSet("1"), toSet("5"), toSet("5"), Boolean.FALSE ); + public HierarchyNode node4 = new HierarchyNode("4", HIERARCHYA, "College of Science", PERM_TOKEN_2, toSet("1"), toSet("1"), toSet("6,7,8"), toSet("6,7,8"), Boolean.FALSE ); + public HierarchyNode node5 = new HierarchyNode("5", HIERARCHYA, "Dept of Art", PERM_TOKEN_1, toSet("3"), toSet("1,3"), toSet(""), toSet(""), Boolean.FALSE ); + public HierarchyNode node6 = new HierarchyNode("6", HIERARCHYA, "Dept of Math", null, toSet("4"), toSet("1,4"), toSet(""), toSet(""), Boolean.FALSE ); + public HierarchyNode node7 = new HierarchyNode("7", HIERARCHYA, "Dept of Physics", null, toSet("4"), toSet("1,4"), toSet(""), toSet(""), Boolean.FALSE ); + public HierarchyNode node8 = new HierarchyNode("8", HIERARCHYA, "Dept of Biology", null, toSet("4"), toSet("1,4"), toSet(""), toSet(""), Boolean.FALSE ); + public HierarchyNode node9 = new HierarchyNode("9", HIERARCHYB, "Univ of BZ", null, toSet(""), toSet(""), toSet("10"), toSet("10"), Boolean.FALSE ); + public HierarchyNode node10 = new HierarchyNode("10", HIERARCHYB, "College of BZ", PERM_TOKEN_1, toSet("9,11"), toSet("9,11"), toSet(""), toSet(""), Boolean.FALSE ); + public HierarchyNode node11 = new HierarchyNode("11", HIERARCHYB, "Provost of BZ", null, toSet(""), toSet(""), toSet("10"), toSet("10"), Boolean.FALSE ); + + + /** + * Encode the comma delimited list of nodes to a set + * @param commaDelimitedNums + * @return sorted set + */ + private Set toSet(String commaDelimitedNums) { + Set s = new TreeSet(); + if (commaDelimitedNums != null && !commaDelimitedNums.equals("")) { + String[] split = commaDelimitedNums.split(","); + for (int i = 0; i < split.length; i++) { + s.add( split[i] ); + } + } + return s; + } + +} diff --git a/hierarchy/impl/pom.xml b/hierarchy/impl/pom.xml new file mode 100644 index 000000000000..e4425d7c706d --- /dev/null +++ b/hierarchy/impl/pom.xml @@ -0,0 +1,223 @@ + + 4.0.0 + + + hierarchy + org.sakaiproject + 10.0-SNAPSHOT + + + Sakai Hierarchy Implementation + org.sakaiproject.hierarchy + hierarchy-impl + jar + + + 0.9.18 + + + + + sakai-10 + + true + + + + + org.hibernate + hibernate-core + + + + org.slf4j + slf4j-api + test + + + org.javassist + javassist + test + + + org.hibernate + hibernate-ehcache + test + + + org.springframework + spring-core + + + org.springframework + spring-beans + + + org.springframework + spring-orm + + + org.springframework + spring-context + + + + + sakai-2.9 + + + + org.springframework + spring + + + org.hibernate + hibernate + + + net.sf.ehcache + ehcache + 1.3.0 + test + + + + + + + + + org.sakaiproject.hierarchy + hierarchy-api + + + + + org.sakaiproject + generic-dao + ${sakai.generic-dao.version} + + + + + org.sakaiproject.kernel + sakai-kernel-api + + + org.sakaiproject.kernel + sakai-component-manager + + + org.sakaiproject.kernel + sakai-kernel-util + + + commons-logging + commons-logging + + + org.hsqldb + hsqldb + test + + + dom4j + dom4j + 1.6.1 + test + + + jta + jta + h2.1.8 + test + + + cglib + cglib-nodep + 2.1_3 + test + + + commons-codec + commons-codec + test + + + commons-collections + commons-collections + 3.2 + test + + + + + org.springframework + spring-mock + 2.0.6 + test + + + easymock + easymock + 1.2_Java1.3 + test + + + commons-lang + commons-lang + test + + + + + + + + ${basedir}/src/bundle + + **/*.properties + + false + + + ${basedir}/src/java + + **/*.xml + + false + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + + + ${basedir}/../pack/src/webapp/WEB-INF + + spring-hibernate.xml + logic-support.xml + + + + ${basedir}/src/test + + hibernate-test.xml + hibernate.properties + + + + + diff --git a/hierarchy/impl/project.xml b/hierarchy/impl/project.xml new file mode 100644 index 000000000000..20617bd6322a --- /dev/null +++ b/hierarchy/impl/project.xml @@ -0,0 +1,170 @@ + + + 3 + ../../master/project.xml + sakai-hierarchy-impl + sakaiproject + sakai-hierarchy-impl + ${sakai.version} + + CARET, Cambridge University + http://caret.cam.ac.uk/ + + 2007 + + + + jar + + + + + + + sakaiproject + sakai + ${sakai.plugin.version} + plugin + + + + + sakaiproject + sakai-hierarchy-api + ${sakai.version} + + + + + generic-dao + generic-dao + 0.9.8 + + + + + ${sakai.spring.groupId} + ${sakai.spring.artifactId} + ${sakai.spring.version} + + + + ${sakai.hibernate.groupId} + ${sakai.hibernate.artifactId} + ${sakai.hibernate.version} + + + + + antlr + antlr + 2.7.6 + + + + + commons-logging + commons-logging + 1.0.4 + + + + + ${sakai.spring.groupId} + ${sakai.spring.mock.artifactId} + ${sakai.spring.mock.version} + + + + hsqldb + hsqldb + 1.8.0.5 + + + + dom4j + dom4j + 1.6.1 + + + + jta + jta + h2.1.8 + + + + cglib + cglib-nodep + 2.1_3 + + + + commons-codec + commons-codec + 1.3 + + + + commons-collections + commons-collections + 3.1 + + + + ehcache + ehcache + 1.1 + + + + easymock + easymock + 1.2_Java1.3 + + + + + + + src/java + + + ${basedir}/src/java + + **/*.xml + + false + + + + + src/test + + + **/*Test.java + + + + ${basedir}/../pack/src/webapp/WEB-INF + + spring-hibernate.xml + logic-support.xml + + + + ${basedir}/src/test + + hibernate-test.xml + hibernate.properties + + + + + + + + + diff --git a/hierarchy/impl/src/ddl/db2/hierarchy.sql b/hierarchy/impl/src/ddl/db2/hierarchy.sql new file mode 100644 index 000000000000..5d5d87c213a0 --- /dev/null +++ b/hierarchy/impl/src/ddl/db2/hierarchy.sql @@ -0,0 +1,41 @@ + + create table HIERARCHY_NODE ( + ID bigint generated by default as identity, + directParentIds varchar(2000), + parentIds varchar(4000), + directChildIds varchar(2000), + childIds varchar(4000), + primary key (ID) + ); + + create table HIERARCHY_NODE_META ( + ID bigint generated by default as identity, + hierarchyId varchar(255), + isRootNode smallint not null, + ownerId varchar(255), + title varchar(255), + description clob(255), + permToken varchar(255), + isDisabled smallint not null, + primary key (ID) + ); + + create table HIERARCHY_PERMS ( + ID bigint generated by default as identity, + createdOn timestamp not null, + lastModified timestamp not null, + userId varchar(255) not null, + nodeId varchar(255) not null, + permission varchar(255) not null, + primary key (ID) + ); + + create index HIERARCHY_PERMTOKEN on HIERARCHY_NODE_META (permToken); + + create index HIERARCHY_HID on HIERARCHY_NODE_META (hierarchyId); + + create index HIER_PERM_USER on HIERARCHY_PERMS (userId); + + create index HIER_PERM_NODE on HIERARCHY_PERMS (nodeId); + + create index HIER_PERM_PERM on HIERARCHY_PERMS (permission); diff --git a/hierarchy/impl/src/ddl/derby/hierarchy.sql b/hierarchy/impl/src/ddl/derby/hierarchy.sql new file mode 100644 index 000000000000..83f17fce1ce7 --- /dev/null +++ b/hierarchy/impl/src/ddl/derby/hierarchy.sql @@ -0,0 +1,47 @@ + + create table HIERARCHY_NODE ( + ID bigint not null, + directParentIds varchar(2000), + parentIds varchar(4000), + directChildIds varchar(2000), + childIds varchar(4000), + primary key (ID) + ); + + create table HIERARCHY_NODE_META ( + ID bigint not null, + hierarchyId varchar(255), + isRootNode smallint not null, + ownerId varchar(255), + title varchar(255), + description clob(255), + permToken varchar(255), + isDisabled smallint not null, + primary key (ID) + ); + + create table HIERARCHY_PERMS ( + ID bigint not null, + createdOn timestamp not null, + lastModified timestamp not null, + userId varchar(255) not null, + nodeId varchar(255) not null, + permission varchar(255) not null, + primary key (ID) + ); + + create index HIERARCHY_PERMTOKEN on HIERARCHY_NODE_META (permToken); + + create index HIERARCHY_HID on HIERARCHY_NODE_META (hierarchyId); + + create index HIER_PERM_USER on HIERARCHY_PERMS (userId); + + create index HIER_PERM_NODE on HIERARCHY_PERMS (nodeId); + + create index HIER_PERM_PERM on HIERARCHY_PERMS (permission); + + create table hibernate_unique_key ( + next_hi integer + ); + + insert into hibernate_unique_key values ( 0 ); diff --git a/hierarchy/impl/src/ddl/hibernate-db2.properties b/hierarchy/impl/src/ddl/hibernate-db2.properties new file mode 100644 index 000000000000..95ad3822a431 --- /dev/null +++ b/hierarchy/impl/src/ddl/hibernate-db2.properties @@ -0,0 +1,2 @@ +# This properties file defines the dialect for the DB2 database +hibernate.dialect=org.hibernate.dialect.DB2Dialect diff --git a/hierarchy/impl/src/ddl/hibernate-derby.properties b/hierarchy/impl/src/ddl/hibernate-derby.properties new file mode 100644 index 000000000000..46c12c678c41 --- /dev/null +++ b/hierarchy/impl/src/ddl/hibernate-derby.properties @@ -0,0 +1,2 @@ +# This properties file defines the dialect for the derby database +hibernate.dialect=org.hibernate.dialect.DerbyDialect diff --git a/hierarchy/impl/src/ddl/hibernate-hsqldb.properties b/hierarchy/impl/src/ddl/hibernate-hsqldb.properties new file mode 100644 index 000000000000..504e2574012b --- /dev/null +++ b/hierarchy/impl/src/ddl/hibernate-hsqldb.properties @@ -0,0 +1,2 @@ +# This properties file defines the dialect for the HSQLDB database +hibernate.dialect=org.hibernate.dialect.HSQLDialect diff --git a/hierarchy/impl/src/ddl/hibernate-mssql.properties b/hierarchy/impl/src/ddl/hibernate-mssql.properties new file mode 100644 index 000000000000..19b465fb7245 --- /dev/null +++ b/hierarchy/impl/src/ddl/hibernate-mssql.properties @@ -0,0 +1,2 @@ +# This properties file defines the dialect for the MSSQL database +hibernate.dialect=org.hibernate.dialect.SQLServerDialect diff --git a/hierarchy/impl/src/ddl/hibernate-mysql.properties b/hierarchy/impl/src/ddl/hibernate-mysql.properties new file mode 100644 index 000000000000..6ebdf8b628c8 --- /dev/null +++ b/hierarchy/impl/src/ddl/hibernate-mysql.properties @@ -0,0 +1,2 @@ +# This properties file defines the dialect for the MYSQL database +hibernate.dialect=org.hibernate.dialect.MySQLDialect diff --git a/hierarchy/impl/src/ddl/hibernate-oracle.properties b/hierarchy/impl/src/ddl/hibernate-oracle.properties new file mode 100644 index 000000000000..01205f4501da --- /dev/null +++ b/hierarchy/impl/src/ddl/hibernate-oracle.properties @@ -0,0 +1,2 @@ +# This properties file defines the dialect for the Oracle database +hibernate.dialect=org.hibernate.dialect.OracleDialect diff --git a/hierarchy/impl/src/ddl/hibernate-postgres.properties b/hierarchy/impl/src/ddl/hibernate-postgres.properties new file mode 100644 index 000000000000..aed39a5fe5a9 --- /dev/null +++ b/hierarchy/impl/src/ddl/hibernate-postgres.properties @@ -0,0 +1,2 @@ +# This properties file defines the dialect for the postgres database +hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect diff --git a/hierarchy/impl/src/ddl/hibernate.cfg.xml b/hierarchy/impl/src/ddl/hibernate.cfg.xml new file mode 100644 index 000000000000..87eacab940e5 --- /dev/null +++ b/hierarchy/impl/src/ddl/hibernate.cfg.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/hierarchy/impl/src/ddl/hsqldb/hierarchy.sql b/hierarchy/impl/src/ddl/hsqldb/hierarchy.sql new file mode 100644 index 000000000000..7ec5cd1e89ce --- /dev/null +++ b/hierarchy/impl/src/ddl/hsqldb/hierarchy.sql @@ -0,0 +1,41 @@ + + create table HIERARCHY_NODE ( + ID bigint generated by default as identity (start with 1), + directParentIds varchar(2000), + parentIds varchar(4000), + directChildIds varchar(2000), + childIds varchar(4000), + primary key (ID) + ); + + create table HIERARCHY_NODE_META ( + ID bigint generated by default as identity (start with 1), + hierarchyId varchar(255), + isRootNode bit not null, + ownerId varchar(255), + title varchar(255), + description longvarchar, + permToken varchar(255), + isDisabled bit not null, + primary key (ID) + ); + + create table HIERARCHY_PERMS ( + ID bigint generated by default as identity (start with 1), + createdOn timestamp not null, + lastModified timestamp not null, + userId varchar(255) not null, + nodeId varchar(255) not null, + permission varchar(255) not null, + primary key (ID) + ); + + create index HIERARCHY_PERMTOKEN on HIERARCHY_NODE_META (permToken); + + create index HIERARCHY_HID on HIERARCHY_NODE_META (hierarchyId); + + create index HIER_PERM_USER on HIERARCHY_PERMS (userId); + + create index HIER_PERM_NODE on HIERARCHY_PERMS (nodeId); + + create index HIER_PERM_PERM on HIERARCHY_PERMS (permission); diff --git a/hierarchy/impl/src/ddl/mssql/hierarchy.sql b/hierarchy/impl/src/ddl/mssql/hierarchy.sql new file mode 100644 index 000000000000..1cfde139d772 --- /dev/null +++ b/hierarchy/impl/src/ddl/mssql/hierarchy.sql @@ -0,0 +1,41 @@ + + create table HIERARCHY_NODE ( + ID numeric(19,0) identity not null, + directParentIds varchar(2000) null, + parentIds varchar(4000) null, + directChildIds varchar(2000) null, + childIds varchar(4000) null, + primary key (ID) + ); + + create table HIERARCHY_NODE_META ( + ID numeric(19,0) identity not null, + hierarchyId varchar(255) null, + isRootNode tinyint not null, + ownerId varchar(255) null, + title varchar(255) null, + description text null, + permToken varchar(255) null, + isDisabled tinyint not null, + primary key (ID) + ); + + create table HIERARCHY_PERMS ( + ID numeric(19,0) identity not null, + createdOn datetime not null, + lastModified datetime not null, + userId varchar(255) not null, + nodeId varchar(255) not null, + permission varchar(255) not null, + primary key (ID) + ); + + create index HIERARCHY_PERMTOKEN on HIERARCHY_NODE_META (permToken); + + create index HIERARCHY_HID on HIERARCHY_NODE_META (hierarchyId); + + create index HIER_PERM_USER on HIERARCHY_PERMS (userId); + + create index HIER_PERM_NODE on HIERARCHY_PERMS (nodeId); + + create index HIER_PERM_PERM on HIERARCHY_PERMS (permission); diff --git a/hierarchy/impl/src/ddl/mysql/hierarchy.sql b/hierarchy/impl/src/ddl/mysql/hierarchy.sql new file mode 100644 index 000000000000..f2b7c02d81ea --- /dev/null +++ b/hierarchy/impl/src/ddl/mysql/hierarchy.sql @@ -0,0 +1,41 @@ + + create table HIERARCHY_NODE ( + ID bigint not null auto_increment, + directParentIds text, + parentIds text, + directChildIds blob, + childIds blob, + primary key (ID) + ); + + create table HIERARCHY_NODE_META ( + ID bigint not null auto_increment, + hierarchyId varchar(255), + isRootNode bit not null, + ownerId varchar(255), + title varchar(255), + description text, + permToken varchar(255), + isDisabled bit not null, + primary key (ID) + ); + + create table HIERARCHY_PERMS ( + ID bigint not null auto_increment, + createdOn datetime not null, + lastModified datetime not null, + userId varchar(255) not null, + nodeId varchar(255) not null, + permission varchar(255) not null, + primary key (ID) + ); + + create index HIERARCHY_PERMTOKEN on HIERARCHY_NODE_META (permToken); + + create index HIERARCHY_HID on HIERARCHY_NODE_META (hierarchyId); + + create index HIER_PERM_USER on HIERARCHY_PERMS (userId); + + create index HIER_PERM_NODE on HIERARCHY_PERMS (nodeId); + + create index HIER_PERM_PERM on HIERARCHY_PERMS (permission); diff --git a/hierarchy/impl/src/ddl/oracle/hierarchy.sql b/hierarchy/impl/src/ddl/oracle/hierarchy.sql new file mode 100644 index 000000000000..ed881630cc7d --- /dev/null +++ b/hierarchy/impl/src/ddl/oracle/hierarchy.sql @@ -0,0 +1,47 @@ + + create table HIERARCHY_NODE ( + ID number(19,0) not null, + directParentIds varchar2(2000), + parentIds varchar2(4000), + directChildIds clob, + childIds clob, + primary key (ID) + ); + + create table HIERARCHY_NODE_META ( + ID number(19,0) not null, + hierarchyId varchar2(255), + isRootNode number(1,0) not null, + ownerId varchar2(255), + title varchar2(255), + description clob, + permToken varchar2(255), + isDisabled number(1,0) not null, + primary key (ID) + ); + + create table HIERARCHY_PERMS ( + ID number(19,0) not null, + createdOn date not null, + lastModified date not null, + userId varchar2(255) not null, + nodeId varchar2(255) not null, + permission varchar2(255) not null, + primary key (ID) + ); + + create index HIERARCHY_PERMTOKEN on HIERARCHY_NODE_META (permToken); + + create index HIERARCHY_HID on HIERARCHY_NODE_META (hierarchyId); + + create index HIER_PERM_USER on HIERARCHY_PERMS (userId); + + create index HIER_PERM_NODE on HIERARCHY_PERMS (nodeId); + + create index HIER_PERM_PERM on HIERARCHY_PERMS (permission); + + create sequence HIERARCHY_META_ID_SEQ; + + create sequence HIERARCHY_NODE_ID_SEQ; + + create sequence HIERARCHY_PERM_ID_SEQ; diff --git a/hierarchy/impl/src/ddl/pom.xml b/hierarchy/impl/src/ddl/pom.xml new file mode 100644 index 000000000000..5b8d524ce547 --- /dev/null +++ b/hierarchy/impl/src/ddl/pom.xml @@ -0,0 +1,160 @@ + + 4.0.0 + + Sakai Hierarchy DB DDL generator + org.sakaiproject.hierarchy + hierarchy-ddl-generator + pom + + + + hierarchy + org.sakaiproject + 10.0-SNAPSHOT + + + + + hierarchy + + + + + + + org.sakaiproject.hierarchy + hierarchy-api + + + + + + + + + ${basedir}/../java + + **/*.xml + + false + + + + + + + org.codehaus.mojo + hibernate3-maven-plugin + 2.1 + + + + hbm2ddl + . + + + + hibernate.cfg.xml + hibernate-hsqldb.properties + hsqldb/${project.ddl.name}.sql + false + true + false + true + true + + + + + export-hsqldb + process-classes + + hbm2ddl + + + + export-mysql + process-classes + + hbm2ddl + + + + hibernate-mysql.properties + mysql/${project.ddl.name}.sql + + + + + export-oracle + process-classes + + hbm2ddl + + + + hibernate-oracle.properties + oracle/${project.ddl.name}.sql + + + + + export-db2 + process-classes + + hbm2ddl + + + + hibernate-db2.properties + db2/${project.ddl.name}.sql + + + + + export-mssql + process-classes + + hbm2ddl + + + + hibernate-mssql.properties + mssql/${project.ddl.name}.sql + + + + + export-derby + process-classes + + hbm2ddl + + + + hibernate-derby.properties + derby/${project.ddl.name}.sql + + + + + export-postgres + process-classes + + hbm2ddl + + + + hibernate-postgres.properties + postgres/${project.ddl.name}.sql + + + + + + + + + diff --git a/hierarchy/impl/src/ddl/postgres/hierarchy.sql b/hierarchy/impl/src/ddl/postgres/hierarchy.sql new file mode 100644 index 000000000000..91354afa33dc --- /dev/null +++ b/hierarchy/impl/src/ddl/postgres/hierarchy.sql @@ -0,0 +1,47 @@ + + create table HIERARCHY_NODE ( + ID int8 not null, + directParentIds varchar(2000), + parentIds varchar(4000), + directChildIds varchar(2000), + childIds varchar(4000), + primary key (ID) + ); + + create table HIERARCHY_NODE_META ( + ID int8 not null, + hierarchyId varchar(255), + isRootNode bool not null, + ownerId varchar(255), + title varchar(255), + description text, + permToken varchar(255), + isDisabled bool not null, + primary key (ID) + ); + + create table HIERARCHY_PERMS ( + ID int8 not null, + createdOn timestamp not null, + lastModified timestamp not null, + userId varchar(255) not null, + nodeId varchar(255) not null, + permission varchar(255) not null, + primary key (ID) + ); + + create index HIERARCHY_PERMTOKEN on HIERARCHY_NODE_META (permToken); + + create index HIERARCHY_HID on HIERARCHY_NODE_META (hierarchyId); + + create index HIER_PERM_USER on HIERARCHY_PERMS (userId); + + create index HIER_PERM_NODE on HIERARCHY_PERMS (nodeId); + + create index HIER_PERM_PERM on HIERARCHY_PERMS (permission); + + create sequence HIERARCHY_META_ID_SEQ; + + create sequence HIERARCHY_NODE_ID_SEQ; + + create sequence HIERARCHY_PERM_ID_SEQ; diff --git a/hierarchy/impl/src/java/org/sakaiproject/hierarchy/dao/HierarchyDao.java b/hierarchy/impl/src/java/org/sakaiproject/hierarchy/dao/HierarchyDao.java new file mode 100644 index 000000000000..2b5f3a05e954 --- /dev/null +++ b/hierarchy/impl/src/java/org/sakaiproject/hierarchy/dao/HierarchyDao.java @@ -0,0 +1,36 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy.dao; + +import org.sakaiproject.genericdao.api.GeneralGenericDao; + +/** + * DAO for access to the database for entity broker internal writes + * + * @author Aaron Zeckoski (aaronz@vt.edu) + */ +public interface HierarchyDao extends GeneralGenericDao { + + /** + * This will apply migration type fixes to the database as needed + */ + public void fixupDatabase(); + +} diff --git a/hierarchy/impl/src/java/org/sakaiproject/hierarchy/dao/HierarchyDaoImpl.java b/hierarchy/impl/src/java/org/sakaiproject/hierarchy/dao/HierarchyDaoImpl.java new file mode 100644 index 000000000000..f9c93ef888c8 --- /dev/null +++ b/hierarchy/impl/src/java/org/sakaiproject/hierarchy/dao/HierarchyDaoImpl.java @@ -0,0 +1,50 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.sakaiproject.genericdao.api.search.Restriction; +import org.sakaiproject.genericdao.api.search.Search; +import org.sakaiproject.genericdao.hibernate.HibernateGeneralGenericDao; + +import org.sakaiproject.hierarchy.dao.model.HierarchyNodeMetaData; + +/** + * Implementation of DAO + * + * @author Aaron Zeckoski (aaronz@vt.edu) + */ +public class HierarchyDaoImpl extends HibernateGeneralGenericDao implements HierarchyDao { + + private static Log log = LogFactory.getLog(HierarchyDaoImpl.class); + + public void fixupDatabase() { + // fix up some of the null fields + long count = 0; + count = countBySearch(HierarchyNodeMetaData.class, new Search("isDisabled","", Restriction.NULL) ); + if (count > 0) { + int counter = 0; + counter += getHibernateTemplate().bulkUpdate("update HierarchyNodeMetaData nm set nm.isDisabled = false where nm.isDisabled is null"); + log.info("Updated " + counter + " HierarchyNodeMetaData.isDisabled fields from null to boolean false"); + } + } +} diff --git a/hierarchy/impl/src/java/org/sakaiproject/hierarchy/dao/ResourceFinder.java b/hierarchy/impl/src/java/org/sakaiproject/hierarchy/dao/ResourceFinder.java new file mode 100644 index 000000000000..7fca19e84f56 --- /dev/null +++ b/hierarchy/impl/src/java/org/sakaiproject/hierarchy/dao/ResourceFinder.java @@ -0,0 +1,92 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy.dao; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + + +/** + * Allows us to find resources in our pack since the Sakai context classloader is wrong, + * too bad it is not correct, that would be cool, but it is wrong and it is not cool
+ * Takes a list of paths to resources and turns them into + * + * @author Aaron Zeckoski (aaron@caret.cam.ac.uk) + */ +public class ResourceFinder { + + private static List makeResources(List paths) { + List rs = new ArrayList(); + if (paths != null && !paths.isEmpty()) { + ClassLoader cl = ResourceFinder.class.getClassLoader(); + for (String path : paths) { + Resource r = new ClassPathResource(path, cl); + if (r.exists()) { + rs.add(r); + } + } + } + return rs; + } + + /** + * Resolves a list of paths into resources within the current classloader + * @param paths a list of paths to resources (org/sakaiproject/mystuff/Thing.xml) + * @return an array of Spring Resource objects + */ + public static Resource[] getResources(List paths) { + return makeResources(paths).toArray(new Resource[] {}); + } + + public static File[] getFiles(List paths) { + List rs = makeResources(paths); + File[] files = new File[rs.size()]; + for (int i = 0; i < rs.size(); i++) { + Resource r = rs.get(i); + try { + files[i] = r.getFile(); + } catch (IOException e) { + throw new RuntimeException("Failed to get file for: " + r.getFilename(), e); + } + } + return files; + } + + public static InputStream[] getInputStreams(List paths) { + List rs = makeResources(paths); + InputStream[] streams = new InputStream[rs.size()]; + for (int i = 0; i < rs.size(); i++) { + Resource r = rs.get(i); + try { + streams[i] = r.getInputStream(); + } catch (IOException e) { + throw new RuntimeException("Failed to get inputstream for: " + r.getFilename(), e); + } + } + return streams; + } + +} diff --git a/hierarchy/impl/src/java/org/sakaiproject/hierarchy/impl/HierarchyServiceImpl.java b/hierarchy/impl/src/java/org/sakaiproject/hierarchy/impl/HierarchyServiceImpl.java new file mode 100644 index 000000000000..69b4be927fa5 --- /dev/null +++ b/hierarchy/impl/src/java/org/sakaiproject/hierarchy/impl/HierarchyServiceImpl.java @@ -0,0 +1,1138 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.sakaiproject.genericdao.api.search.Order; +import org.sakaiproject.genericdao.api.search.Restriction; +import org.sakaiproject.genericdao.api.search.Search; +import org.sakaiproject.hierarchy.HierarchyService; +import org.sakaiproject.hierarchy.dao.HierarchyDao; +import org.sakaiproject.hierarchy.dao.model.HierarchyNodeMetaData; +import org.sakaiproject.hierarchy.dao.model.HierarchyNodePermission; +import org.sakaiproject.hierarchy.dao.model.HierarchyPersistentNode; +import org.sakaiproject.hierarchy.impl.utils.HierarchyImplUtils; +import org.sakaiproject.hierarchy.model.HierarchyNode; +import org.sakaiproject.db.api.SqlService; + +/** + * The default implementation of the Hierarchy interface + * + * @author Aaron Zeckoski (aaronz@vt.edu) + */ +public class HierarchyServiceImpl implements HierarchyService { + + private static Log log = LogFactory.getLog(HierarchyServiceImpl.class); + + private static int ORACLE_IN_CLAUSE_SIZE_LIMIT = 1000; + private boolean oracle = false; + + private HierarchyDao dao; + + public void setDao(HierarchyDao dao) { + this.dao = dao; + } + + private SqlService sqlService; + + public void setSqlService(SqlService sqlService) { + this.sqlService = sqlService; + } + + // private SessionManager sessionManager; + // public void setSessionManager(SessionManager sessionManager) { + // this.sessionManager = sessionManager; + // } + + public void init() { + log.info("init"); + + if(sqlService != null && "oracle".equalsIgnoreCase(sqlService.getVendor())){ + this.oracle = true; + } + + // handle any DB migration/cleanup which needs to happen (mostly for upgrades) + dao.fixupDatabase(); + } + + public HierarchyNode createHierarchy(String hierarchyId) { + if (hierarchyId.length() < 1 || hierarchyId.length() > 250) { + throw new IllegalArgumentException("Invalid hierarchyId (" + hierarchyId + + "): length must be 1 to 250 chars"); + } + + long count = dao.countBySearch(HierarchyNodeMetaData.class, + new Search("hierarchyId", hierarchyId) ); + if (count > 0) { + throw new IllegalArgumentException("Invalid hierarchyId (" + hierarchyId + + "): this id is already in use, you must use a unique id when creating a new hierarchy"); + } + + HierarchyPersistentNode pNode = new HierarchyPersistentNode(); // no children or parents to + // start + HierarchyNodeMetaData metaData = new HierarchyNodeMetaData(pNode, hierarchyId, Boolean.TRUE, null); // getCurrentUserId()); + saveNodeAndMetaData(pNode, metaData); + + return HierarchyImplUtils.makeNode(pNode, metaData); + } + + public HierarchyNode setHierarchyRootNode(String hierarchyId, String nodeId) { + HierarchyNodeMetaData metaData = getNodeMeta(nodeId); + HierarchyNodeMetaData rootMetaData = getRootNodeMetaByHierarchy(hierarchyId); + + Set entities = new HashSet(); + + if (rootMetaData != null) { + if (metaData.getId().equals(rootMetaData.getId())) { + // this node is already the root node + return HierarchyImplUtils.makeNode(metaData); + } else if (!metaData.getHierarchyId().equals(rootMetaData.getHierarchyId())) { + throw new IllegalArgumentException("Cannot move a node from one hierarchy (" + + metaData.getHierarchyId() + ") to another (" + hierarchyId + + ") and replace the root node, this could orphan nodes"); + } + rootMetaData.setIsRootNode(Boolean.FALSE); + entities.add(metaData); + } + + if (metaData.getNode().getParentIds() != null) { + throw new IllegalArgumentException("Cannot assign a node (" + nodeId + + ") to the hierarchy rootNode when it has parents"); + } + + metaData.setIsRootNode(Boolean.TRUE); + entities.add(metaData); + + dao.saveSet(entities); + return HierarchyImplUtils.makeNode(metaData); + } + + @SuppressWarnings("rawtypes") + public void destroyHierarchy(String hierarchyId) { + List l = dao.findBySearch(HierarchyNodeMetaData.class, + new Search("hierarchyId", hierarchyId) ); + if (l.isEmpty()) { + throw new IllegalArgumentException("Could not find hierarchy to remove with the following id: " + + hierarchyId); + } + + Set nodes = new HashSet(); + Set nodesMetaData = new HashSet(); + for (int i = 0; i < l.size(); i++) { + HierarchyNodeMetaData nmd = (HierarchyNodeMetaData) l.get(i); + nodesMetaData.add(nmd); + nodes.add(nmd.getNode()); + } + + Set[] entitySets = new Set[] { nodesMetaData, nodes }; + dao.deleteMixedSet(entitySets); + } + + public HierarchyNode getRootNode(String hierarchyId) { + HierarchyNodeMetaData metaData = getRootNodeMetaByHierarchy(hierarchyId); + if (metaData == null) { + return null; + } + return HierarchyImplUtils.makeNode(metaData); + } + + public HierarchyNode getNodeById(String nodeId) { + HierarchyNodeMetaData metaData = getNodeMeta(nodeId); + return HierarchyImplUtils.makeNode(metaData); + } + + + public Map getNodesByIds(String[] nodeIds) { + List nodeMetas = getNodeMetas(nodeIds); + Map m = new HashMap(); + for (HierarchyNodeMetaData metaData : nodeMetas) { + HierarchyNode node = HierarchyImplUtils.makeNode(metaData); + m.put(node.id, node); + } + return m; + } + + public Set getChildNodes(String nodeId, boolean directOnly) { + Set children = new HashSet(); + + HierarchyNodeMetaData parentMetaData = getNodeMeta(nodeId); + String childIdString = null; + if (directOnly) { + childIdString = parentMetaData.getNode().getDirectChildIds(); + } else { + childIdString = parentMetaData.getNode().getChildIds(); + } + + if (childIdString == null) { + return children; + } + + Set childrenIds = HierarchyImplUtils.makeNodeIdSet(childIdString); + List childNodeMetas = getNodeMetas(childrenIds); + for (HierarchyNodeMetaData metaData : childNodeMetas) { + children.add(HierarchyImplUtils.makeNode(metaData)); + } + return children; + } + + public Set getParentNodes(String nodeId, boolean directOnly) { + Set parents = new HashSet(); + + HierarchyNodeMetaData parentMetaData = getNodeMeta(nodeId); + String parentIdString = null; + if (directOnly) { + parentIdString = parentMetaData.getNode().getDirectParentIds(); + } else { + parentIdString = parentMetaData.getNode().getParentIds(); + } + + if (parentIdString == null) { + return parents; + } + + Set parentsIds = HierarchyImplUtils.makeNodeIdSet(parentIdString); + List parentNodeMetas = getNodeMetas(parentsIds); + for (HierarchyNodeMetaData metaData : parentNodeMetas) { + parents.add(HierarchyImplUtils.makeNode(metaData)); + } + + + return parents; + } + + public HierarchyNode addNode(String hierarchyId, String parentNodeId) { + if (parentNodeId == null) { + throw new RuntimeException("Setting parentNodeId to null is not yet supported"); + } + + // validate the parent node and hierarchy (this needs to be cached for sure) + HierarchyNodeMetaData parentNodeMeta = getNodeMeta(parentNodeId); + if (parentNodeMeta == null) { + throw new IllegalArgumentException("Invalid parent node id, cannot find node with id: " + + parentNodeId); + } + if (!parentNodeMeta.getHierarchyId().equals(hierarchyId)) { + throw new IllegalArgumentException("Invalid hierarchy id, cannot find node (" + parentNodeId + + ") in this hierarchy: " + hierarchyId); + } + + // get the set of all nodes above the new node (these will have to be updated) + Set parentNodeIds = HierarchyImplUtils.makeNodeIdSet(parentNodeMeta.getNode().getParentIds()); + parentNodeIds.add(parentNodeId); + + // create the new node and assign the new parents from our parent + HierarchyPersistentNode pNode = new HierarchyPersistentNode(HierarchyImplUtils + .makeSingleEncodedNodeIdString(parentNodeId), HierarchyImplUtils + .makeEncodedNodeIdString(parentNodeIds)); + HierarchyNodeMetaData metaData = new HierarchyNodeMetaData(pNode, hierarchyId, Boolean.FALSE, null); // getCurrentUserId()); + // save this new node (perhaps we should be saving all of these in one massive update?) -AZ + saveNodeAndMetaData(pNode, metaData); + String newNodeId = pNode.getId().toString(); + + // update all the links in the tree for this new node + List pNodesList = getNodes(parentNodeIds); + Set pNodes = new HashSet(); + for (HierarchyPersistentNode node : pNodesList) { + if (node.getId().toString().equals(parentNodeId)) { + // special case for our parent, update direct children + node.setDirectChildIds( + HierarchyImplUtils.addSingleNodeIdToEncodedString( + node.getDirectChildIds(), newNodeId)); + } + + // update the children for each node + node.setChildIds( + HierarchyImplUtils.addSingleNodeIdToEncodedString(node.getChildIds(), newNodeId)); + + // add to the set of node to be saved + pNodes.add(node); + } + dao.saveSet(pNodes); + + return HierarchyImplUtils.makeNode(pNode, metaData); + } + + public HierarchyNode removeNode(String nodeId) { + if (nodeId == null) { + throw new NullPointerException("nodeId to remove cannot be null"); + } + + // validate the node + HierarchyNodeMetaData metaData = getNodeMeta(nodeId); + if (metaData == null) { + throw new IllegalArgumentException("Invalid node id, cannot find node with id: " + nodeId); + } + if (metaData.getIsRootNode().booleanValue()) { + throw new IllegalArgumentException("Cannot remove the root node (" + nodeId + "), " + + "you must remove the entire hierarchy (" + metaData.getHierarchyId() + + ") to remove this root node"); + } + + // get the set of all nodes above the current node (these will have to be updated) + HierarchyNode currentNode = HierarchyImplUtils.makeNode(metaData); + if (currentNode.childNodeIds.size() != 0) { + throw new IllegalArgumentException("Cannot remove a node with children nodes, " + + "reduce the children on this node from " + currentNode.childNodeIds.size() + + " to 0 before attempting to remove it"); + } + + if (currentNode.directParentNodeIds.size() > 1) { + throw new IllegalArgumentException("Cannot remove a node with multiple parents, " + + "reduce the parents on this node to 1 before attempting to remove it"); + } + + // get the "main" parent node + String currentParentNodeId = getParentNodeId(currentNode); + + // update all the links in the tree for this removed node + List pNodesList = getNodes(currentNode.parentNodeIds); + Set pNodes = new HashSet(); + for (HierarchyPersistentNode pNode : pNodesList) { + if (pNode.getId().toString().equals(currentParentNodeId)) { + // special case for our parent, update direct children + Set nodeChildren = HierarchyImplUtils.makeNodeIdSet(pNode.getDirectChildIds()); + nodeChildren.remove(nodeId); + pNode.setDirectChildIds(HierarchyImplUtils.makeEncodedNodeIdString(nodeChildren)); + } + + // update the children for each node + Set nodeChildren = HierarchyImplUtils.makeNodeIdSet(pNode.getChildIds()); + nodeChildren.remove(nodeId); + pNode.setChildIds(HierarchyImplUtils.makeEncodedNodeIdString(nodeChildren)); + + // add to the set of nodes to be saved + pNodes.add(pNode); + } + dao.saveSet(pNodes); + + return HierarchyImplUtils.makeNode(getNodeMeta(currentParentNodeId)); + } + + public HierarchyNode saveNodeMetaData(String nodeId, String title, String description, String permToken) { + if (nodeId == null) { + throw new NullPointerException("nodeId to remove cannot be null"); + } + + // validate the node + HierarchyNodeMetaData metaData = getNodeMeta(nodeId); + if (metaData == null) { + throw new IllegalArgumentException("Invalid node id, cannot find node with id: " + nodeId); + } + + // update the node meta data + if (title != null) { + if (title.equals("")) { + metaData.setTitle(null); + } else { + metaData.setTitle(title); + } + } + if (description != null) { + if (description.equals("")) { + metaData.setDescription(null); + } else { + metaData.setDescription(description); + } + } + if (permToken != null) { + if (permToken.equals("")) { + metaData.setPermToken(null); + } else { + metaData.setPermToken(permToken); + } + } + + // save the node meta data + dao.save(metaData); + + return HierarchyImplUtils.makeNode(metaData); + } + + public HierarchyNode setNodeDisabled(String nodeId, Boolean isDisabled) { + + if (nodeId == null) { + throw new NullPointerException("nodeId cannot be null"); + } + + // validate the node + HierarchyNodeMetaData metaData = getNodeMeta(nodeId); + + if (metaData == null) { + throw new IllegalArgumentException("Invalid node id, cannot find node with id: " + nodeId); + } + + // update the node's isDisabled setting + if (isDisabled != null) { + metaData.setIsDisabled(isDisabled); + } + + // save the node meta data + dao.save(metaData); + + return HierarchyImplUtils.makeNode(metaData); + + } + + public HierarchyNode addChildRelation(String nodeId, String childNodeId) { + if (nodeId == null || childNodeId == null) { + throw new NullPointerException("nodeId (" + nodeId + ") and childNodeId (" + childNodeId + + ") cannot be null"); + } + + if (nodeId.equals(childNodeId)) { + throw new IllegalArgumentException("nodeId and childNodeId cannot be the same: " + nodeId); + } + + HierarchyNodeMetaData metaData = getNodeMeta(nodeId); + if (metaData == null) { + throw new IllegalArgumentException("Invalid nodeId: " + nodeId); + } + + HierarchyNodeMetaData addMetaData = getNodeMeta(childNodeId); + if (addMetaData == null) { + throw new IllegalArgumentException("Invalid childNodeId: " + childNodeId); + } + + HierarchyNode currentNode = HierarchyImplUtils.makeNode(metaData); + // only add this if it is not already in there + if (!currentNode.directChildNodeIds.contains(childNodeId)) { + // first check for a cycle + if (currentNode.childNodeIds.contains(childNodeId) + || currentNode.parentNodeIds.contains(childNodeId)) { + throw new IllegalArgumentException("Cannot add " + childNodeId + " as a child of " + nodeId + + " because it is already in the node tree directly above or below this node"); + } + + // now we go ahead and update this node and all the related nodes + HierarchyNode addNode = HierarchyImplUtils.makeNode(addMetaData); + Set pNodes = new HashSet(); + + // update the current node + metaData.getNode().setDirectChildIds( + HierarchyImplUtils.addSingleNodeIdToEncodedString( + metaData.getNode().getDirectChildIds(), childNodeId)); + metaData.getNode().setChildIds( + HierarchyImplUtils.addSingleNodeIdToEncodedString( + metaData.getNode().getChildIds(), childNodeId)); + pNodes.add(metaData.getNode()); + + // update the add node + addMetaData.getNode().setDirectParentIds( + HierarchyImplUtils.addSingleNodeIdToEncodedString( + addMetaData.getNode().getDirectParentIds(), nodeId)); + addMetaData.getNode().setParentIds( + HierarchyImplUtils.addSingleNodeIdToEncodedString( + addMetaData.getNode().getParentIds(),nodeId)); + pNodes.add(addMetaData.getNode()); + + // update the parents of the current node (they have new children) + List pNodesList = getNodes(currentNode.parentNodeIds); + Set nodesToAdd = addNode.childNodeIds; + nodesToAdd.add(addNode.id); + for (HierarchyPersistentNode pNode : pNodesList) { + // update the children for each node + Set nodeChildren = HierarchyImplUtils.makeNodeIdSet(pNode.getChildIds()); + nodeChildren.addAll(nodesToAdd); + pNode.setChildIds(HierarchyImplUtils.makeEncodedNodeIdString(nodeChildren)); + + // add to the set of nodes to be saved + pNodes.add(pNode); + } + + // update the children of the add node (they have new parants) + pNodesList = getNodes(addNode.childNodeIds); + nodesToAdd = currentNode.parentNodeIds; + nodesToAdd.add(currentNode.id); + for (HierarchyPersistentNode pNode : pNodesList) { + // update the parents for each node + Set parents = HierarchyImplUtils.makeNodeIdSet(pNode.getParentIds()); + parents.addAll(nodesToAdd); + pNode.setParentIds(HierarchyImplUtils.makeEncodedNodeIdString(parents)); + + // add to the set of nodes to be saved + pNodes.add(pNode); + } + + dao.saveSet(pNodes); + } + + return HierarchyImplUtils.makeNode(metaData); + } + + public HierarchyNode removeChildRelation(String nodeId, String childNodeId) { + if (nodeId == null || childNodeId == null) { + throw new NullPointerException("nodeId (" + nodeId + ") and childNodeId (" + childNodeId + + ") cannot be null"); + } + + if (nodeId.equals(childNodeId)) { + throw new IllegalArgumentException("nodeId and childNodeId cannot be the same: " + nodeId); + } + + HierarchyNodeMetaData metaData = getNodeMeta(nodeId); + if (metaData == null) { + throw new IllegalArgumentException("Invalid nodeId: " + nodeId); + } + + HierarchyNodeMetaData removeMetaData = getNodeMeta(childNodeId); + if (removeMetaData == null) { + throw new IllegalArgumentException("Invalid childNodeId: " + childNodeId); + } + + HierarchyNode currentNode = HierarchyImplUtils.makeNode(metaData); + // only do something if this child is a direct child of this node + if (currentNode.directChildNodeIds.contains(childNodeId)) { + // first check for orphaning + HierarchyNode removeNode = HierarchyImplUtils.makeNode(removeMetaData); + if (removeNode.directParentNodeIds.size() <= 1) { + throw new IllegalArgumentException("Cannot remove " + childNodeId + " as a child of " + nodeId + + " because it would orphan the child node, you need to use the remove method" + + "if you want to remove a node or add this node as the child of another node first"); + } + + // now we go ahead and update this node and all the related nodes + Set pNodes = new HashSet(); + Set nodes = null; + + // update the current node + nodes = HierarchyImplUtils.makeNodeIdSet(metaData.getNode().getChildIds()); + nodes.remove(childNodeId); + metaData.getNode().setChildIds(HierarchyImplUtils.makeEncodedNodeIdString(nodes)); + nodes = HierarchyImplUtils.makeNodeIdSet(metaData.getNode().getDirectChildIds()); + nodes.remove(childNodeId); + metaData.getNode().setDirectChildIds(HierarchyImplUtils.makeEncodedNodeIdString(nodes)); + pNodes.add(metaData.getNode()); + + // update the remove node + nodes = HierarchyImplUtils.makeNodeIdSet(removeMetaData.getNode().getParentIds()); + nodes.remove(nodeId); + removeMetaData.getNode().setParentIds(HierarchyImplUtils.makeEncodedNodeIdString(nodes)); + nodes = HierarchyImplUtils.makeNodeIdSet(removeMetaData.getNode().getDirectParentIds()); + nodes.remove(nodeId); + removeMetaData.getNode().setDirectParentIds(HierarchyImplUtils.makeEncodedNodeIdString(nodes)); + pNodes.add(removeMetaData.getNode()); + + // update the parents of the current node (they have less children) + List pNodesList = getNodes(currentNode.parentNodeIds); + Set nodesToRemove = removeNode.childNodeIds; + nodesToRemove.add(removeNode.id); + for (HierarchyPersistentNode pNode : pNodesList) { + // update the children for each node + Set children = HierarchyImplUtils.makeNodeIdSet(pNode.getChildIds()); + children.removeAll(nodesToRemove); + // add back in all the children of the currentNode because we may have + // taken out part of the tree below where if it connects to the children of removeNode + children.addAll(currentNode.childNodeIds); + pNode.setChildIds(HierarchyImplUtils.makeEncodedNodeIdString(children)); + + // add to the set of nodes to be saved + pNodes.add(pNode); + } + + // update the children of the remove node (they have lost parents) + pNodesList = getNodes(removeNode.childNodeIds); + nodesToRemove = currentNode.parentNodeIds; + nodesToRemove.add(currentNode.id); + for (HierarchyPersistentNode pNode : pNodesList) { + // update the parents for each node + Set parents = HierarchyImplUtils.makeNodeIdSet(pNode.getParentIds()); + parents.removeAll(nodesToRemove); + // add back in all the parents of the removeNode because we will have + // taken out part of the tree above where it reconnects on the way to the root + parents.addAll(removeNode.parentNodeIds); + pNode.setParentIds(HierarchyImplUtils.makeEncodedNodeIdString(parents)); + + // add to the set of nodes to be saved + pNodes.add(pNode); + } + + dao.saveSet(pNodes); + + } + + return HierarchyImplUtils.makeNode(metaData); + } + + public HierarchyNode addParentRelation(String nodeId, String parentNodeId) { + // TODO Not implemented yet - not sure we even want to allow this + throw new RuntimeException("This method is not implemented yet"); + } + + public HierarchyNode removeParentRelation(String nodeId, String parentNodeId) { + // TODO Not implemented yet - not sure this is even a good idea + throw new RuntimeException("This method is not implemented yet"); + } + + + public Set getNodesWithToken(String hierarchyId, String permToken) { + if (permToken == null || permToken.equals("")) { + throw new NullPointerException("permToken cannot be null or empty string"); + } + + List l = dao.findBySearch(HierarchyNodeMetaData.class, + new Search("hierarchyId", hierarchyId) ); + if (l.isEmpty()) { + throw new IllegalArgumentException("Could not find hierarchy with the following id: " + + hierarchyId); + } + + List nodeIdsList = dao.findBySearch(HierarchyNodeMetaData.class, + new Search(new Restriction[] { + new Restriction("hierarchyId", hierarchyId), + new Restriction("permToken", permToken) + }, new Order("node.id"))); + + Set nodeIds = new TreeSet(); + for (Iterator iter = nodeIdsList.iterator(); iter.hasNext();) { + HierarchyNodeMetaData metaData = iter.next(); + nodeIds.add(metaData.getNode().getId().toString()); + } + + return nodeIds; + } + + public Map> getNodesWithTokens(String hierarchyId, String[] permTokens) { + // it would be better if this were more efficient... + if (permTokens == null) { + throw new NullPointerException("permTokens cannot be null"); + } + + Map> tokenNodes = new HashMap>(); + for (int i = 0; i < permTokens.length; i++) { + Set nodeIds = getNodesWithToken(hierarchyId, permTokens[i]); + tokenNodes.put(permTokens[i], nodeIds); + } + + return tokenNodes; + } + + // PERMISSIONS + + public void assignUserNodePerm(String userId, String nodeId, String hierarchyPermission, boolean cascade) { + if (userId == null || "".equals(userId) + || nodeId == null || "".equals(nodeId) + || hierarchyPermission == null || "".equals(hierarchyPermission)) { + throw new IllegalArgumentException("Invalid arguments to assignUserNodePerm, no arguments can be null or blank: userId="+userId+", nodeId="+nodeId+", hierarchyPermission="+hierarchyPermission); + } + HierarchyNodePermission nodePerm = dao.findOneBySearch(HierarchyNodePermission.class, new Search( + new Restriction[] { + new Restriction("userId", userId), + new Restriction("nodeId", nodeId), + new Restriction("permission", hierarchyPermission) + })); + if (nodePerm == null) { + // validate the nodeId + Long nodeIdeNum; + try { + nodeIdeNum = new Long(nodeId); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Node id ("+nodeId+") provided is invalid, must be a valid identifier from an existing node"); + } + // check it exists + HierarchyPersistentNode pNode = dao.findById(HierarchyPersistentNode.class, nodeIdeNum); + if (pNode == null) { + throw new IllegalArgumentException("Node id ("+nodeId+") provided is invalid, node does not exist"); + } + // create the perm + dao.create( new HierarchyNodePermission(userId, nodeId, hierarchyPermission) ); + } else { + // permission already set, do nothing + } + if (cascade) { + // cascade the permission creation + HierarchyNode node = getNodeById(nodeId); + if (node != null + && node.childNodeIds != null + && node.childNodeIds.size() > 0) { + List nodeIdsList = new ArrayList(node.childNodeIds); + + int i = 0; + List nodePerms = new ArrayList(); + do{ + int arraySize = nodeIdsList.size() - i; + if(oracle && arraySize > ORACLE_IN_CLAUSE_SIZE_LIMIT){ + arraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT; + } + // get all the permissions which are related to the nodes under this one + List nodePermsItteration = dao.findBySearch(HierarchyNodePermission.class, new Search( + new Restriction[] { + new Restriction("userId", userId), + new Restriction("permission", hierarchyPermission), + new Restriction("nodeId", nodeIdsList.subList(i, i + arraySize).toArray()) + })); + nodePerms.addAll(nodePermsItteration); + i += arraySize; + }while(i < nodeIdsList.size()); + + Set allPerms = new HashSet(); + if (nodePerms.size() == 0) { + // add all new ones + for (String childNodeId : node.childNodeIds) { + allPerms.add( new HierarchyNodePermission(userId, childNodeId, hierarchyPermission) ); + } + } else { + // only add the missing ones + Set existingPermNodeIds = new HashSet(); + for (HierarchyNodePermission hierNodePerm : nodePerms) { + existingPermNodeIds.add( hierNodePerm.getNodeId() ); + } + for (String childNodeId : node.childNodeIds) { + if (! existingPermNodeIds.contains(nodeId)) { + allPerms.add( new HierarchyNodePermission(userId, childNodeId, hierarchyPermission) ); + } + } + } + if (nodePerms.size() == node.childNodeIds.size() + || allPerms.size() == 0) { + // nothing to do here, all permissions already exist or there are none to add + } else { + // save the new permissions + dao.saveSet( new HashSet(allPerms) ); + } + } + } + } + + public void removeUserNodePerm(String userId, String nodeId, String hierarchyPermission, boolean cascade) { + if (userId == null || "".equals(userId) + || nodeId == null || "".equals(nodeId) + || hierarchyPermission == null || "".equals(hierarchyPermission)) { + throw new IllegalArgumentException("Invalid arguments to removeUserNodePerm, no arguments can be null or blank: userId="+userId+", nodeId="+nodeId+", hierarchyPermission="+hierarchyPermission); + } + if (! cascade) { + // delete the current permission if it can be found + HierarchyNodePermission nodePerm = dao.findOneBySearch(HierarchyNodePermission.class, new Search( + new Restriction[] { + new Restriction("userId", userId), + new Restriction("nodeId", nodeId), + new Restriction("permission", hierarchyPermission) + })); + if (nodePerm == null) { + // not found, nothing to do + } else { + dao.delete(nodePerm); + } + } else { + // cascade the permission removal and delete current one as well + HierarchyNode node = getNodeById(nodeId); + if (node != null) { + HashSet nodeIdsSet = new HashSet(); + nodeIdsSet.add(nodeId); + // add in child nodes if there are any + if (node.childNodeIds != null + && node.childNodeIds.size() > 0) { + nodeIdsSet.addAll(node.childNodeIds); + } + List nodeIdsList = new ArrayList(nodeIdsSet); + int i = 0; + do{ + int arraySize = nodeIdsList.size() - i; + if(oracle && arraySize > ORACLE_IN_CLAUSE_SIZE_LIMIT){ + arraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT; + } + // get all the permissions which are related to the nodes under this one + List nodePerms = dao.findBySearch(HierarchyNodePermission.class, new Search( + new Restriction[] { + new Restriction("userId", userId), + new Restriction("permission", hierarchyPermission), + new Restriction("nodeId", nodeIdsList.subList(i, i + arraySize).toArray()) + })); + if (nodePerms.size() > 0) { + // delete all as one operation + dao.deleteSet( new HashSet(nodePerms) ); + } + i += arraySize; + }while(i < nodeIdsList.size()); + } + } + } + + public boolean checkUserNodePerm(String userId, String nodeId, String hierarchyPermission) { + if (userId == null || "".equals(userId) + || nodeId == null || "".equals(nodeId) + || hierarchyPermission == null || "".equals(hierarchyPermission)) { + throw new IllegalArgumentException("Invalid arguments to checkUserNodePerm, no arguments can be null or blank: userId="+userId+", nodeId="+nodeId+", hierarchyPermission="+hierarchyPermission); + } + boolean allowed = false; + HierarchyNodePermission nodePerm = dao.findOneBySearch(HierarchyNodePermission.class, new Search( + new Restriction[] { + new Restriction("userId", userId), + new Restriction("nodeId", nodeId), + new Restriction("permission", hierarchyPermission) + })); + if (nodePerm != null) { + allowed = true; + } + return allowed; + } + + public Set getNodesForUserPerm(String userId, String hierarchyPermission) { + if (userId == null || "".equals(userId) + || hierarchyPermission == null || "".equals(hierarchyPermission)) { + throw new IllegalArgumentException("Invalid arguments to getNodesForUserPerm, no arguments can be null or blank: userId="+userId+", hierarchyPermission="+hierarchyPermission); + } + Set nodes = new HashSet(); + List nodePerms = dao.findBySearch(HierarchyNodePermission.class, new Search( + new Restriction[] { + new Restriction("userId", userId), + new Restriction("permission", hierarchyPermission) + })); + Set nodeIds = new HashSet(); + for (HierarchyNodePermission nodePerm : nodePerms) { + nodeIds.add( nodePerm.getNodeId() ); + } + List nodeMetas = getNodeMetas(nodeIds); + for (HierarchyNodeMetaData metaData : nodeMetas) { + nodes.add( HierarchyImplUtils.makeNode(metaData) ); + } + return nodes; + } + + public Set getUserIdsForNodesPerm(String[] nodeIds, String hierarchyPermission) { + if (nodeIds == null + || hierarchyPermission == null || "".equals(hierarchyPermission)) { + throw new IllegalArgumentException("Invalid arguments to getUserIdsForNodesPerm, no arguments can be null or blank: hierarchyPermission="+hierarchyPermission); + } + Set userIds = new HashSet(); + if (nodeIds.length > 0) { + List nodeIdsList = new ArrayList(Arrays.asList(nodeIds)); + int i = 0; + do{ + int arraySize = nodeIdsList.size() - i; + if(oracle && arraySize > ORACLE_IN_CLAUSE_SIZE_LIMIT){ + arraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT; + } + List nodePerms = dao.findBySearch(HierarchyNodePermission.class, new Search( + new Restriction[] { + new Restriction("nodeId", nodeIdsList.subList(i, i + arraySize).toArray()), + new Restriction("permission", hierarchyPermission) + })); + for (HierarchyNodePermission nodePerm : nodePerms) { + userIds.add( nodePerm.getUserId() ); + } + i += arraySize; + }while(i < nodeIdsList.size()); + } + return userIds; + } + + public Set getPermsForUserNodes(String userId, String[] nodeIds) { + if (userId == null || "".equals(userId) + || nodeIds == null ) { + throw new IllegalArgumentException("Invalid arguments to getPermsForUserNodes, no arguments can be null or blank: userId="+userId); + } + Set perms = new HashSet(); + if (nodeIds.length > 0) { + List nodeIdsList = new ArrayList(Arrays.asList(nodeIds)); + int i = 0; + do{ + int arraySize = nodeIdsList.size() - i; + if(oracle && arraySize > ORACLE_IN_CLAUSE_SIZE_LIMIT){ + arraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT; + } + List nodePerms = dao.findBySearch(HierarchyNodePermission.class, new Search( + new Restriction[] { + new Restriction("userId", userId), + new Restriction("nodeId", nodeIdsList.subList(i, i + arraySize).toArray()) + })); + for (HierarchyNodePermission nodePerm : nodePerms) { + perms.add( nodePerm.getPermission() ); + } + i += arraySize; + }while(i < nodeIdsList.size()); + } + return perms; + } + + public Map>> getUsersAndPermsForNodes(String... nodeIds) { + if (nodeIds == null || nodeIds.length == 0) { + throw new IllegalArgumentException("Invalid arguments to getUsersAndPermsForNodes, no arguments can be null or blank: nodeIds="+nodeIds); + } + Map>> m = new HashMap>>(); + for (String nodeId : nodeIds) { + m.put(nodeId, new HashMap>()); + } + List nodePerms = new ArrayList(); + List nodeIdsList = new ArrayList(Arrays.asList(nodeIds)); + int i = 0; + do{ + int arraySize = nodeIdsList.size() - i; + if(oracle && arraySize > ORACLE_IN_CLAUSE_SIZE_LIMIT){ + arraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT; + } + List nodePermsItteration = dao.findBySearch(HierarchyNodePermission.class, + new Search("nodeId", nodeIdsList.subList(i, i + arraySize).toArray())); + nodePerms.addAll(nodePermsItteration); + i += arraySize; + }while(i < nodeIdsList.size()); + + // nodeId -> (map of userId -> Set(permission)) + for (HierarchyNodePermission nodePerm : nodePerms) { + String nodeId = nodePerm.getNodeId(); + if (! m.containsKey(nodeId)) { + continue; // this should not really happen but better safe than sorry + } + String userId = nodePerm.getUserId(); + if (! m.get(nodeId).containsKey(userId) ) { + m.get(nodeId).put(userId, new HashSet() ); + } + m.get(nodeId).get(userId).add( nodePerm.getPermission() ); + } + return m; + } + + public Map>> getNodesAndPermsForUser(String... userIds) { + if (userIds == null || userIds.length == 0) { + throw new IllegalArgumentException("Invalid arguments to getNodesAndPermsForUser, no arguments can be null or blank: userIds="+userIds); + } + Map>> m = new HashMap>>(); + for (String userId : userIds) { + m.put(userId, new HashMap>()); + } + List userIdsList = new ArrayList(Arrays.asList(userIds)); + int i = 0; + List nodePerms = new ArrayList(); + do{ + int arraySize = userIdsList.size() - i; + if(oracle && arraySize > ORACLE_IN_CLAUSE_SIZE_LIMIT){ + arraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT; + } + List nodePermsItteration = dao.findBySearch(HierarchyNodePermission.class, + new Search("userId", userIdsList.subList(i, i + arraySize).toArray())); + nodePerms.addAll(nodePermsItteration); + i += arraySize; + }while(i < userIdsList.size()); + + // userId -> (map of nodeId -> Set(permission)) + for (HierarchyNodePermission nodePerm : nodePerms) { + String userId = nodePerm.getUserId(); + if (! m.containsKey(userId)) { + continue; // this should not really happen but better safe than sorry + } + String nodeId = nodePerm.getNodeId(); + if (! m.get(userId).containsKey(nodeId) ) { + m.get(userId).put(nodeId, new HashSet() ); + } + m.get(userId).get(nodeId).add( nodePerm.getPermission() ); + } + return m; + } + + // PRIVATE + + + /** + * Convenience method to save a node and metadata in one transaction + * + * @param pNode + * @param metaData + */ + @SuppressWarnings("rawtypes") + private void saveNodeAndMetaData(HierarchyPersistentNode pNode, HierarchyNodeMetaData metaData) { + Set pNodes = new HashSet(); + pNodes.add(pNode); + Set metaDatas = new HashSet(); + metaDatas.add(metaData); + Set[] entitySets = new Set[] { pNodes, metaDatas }; + dao.saveMixedSet(entitySets); + /* NORMALLY the code below should not be needed, however, + * we are seeing weird cases where the line above fails to create the metadata + * so the code below is meant to detect that case and correct it by saving + * each separately and realigning the ids manually + */ + if (metaData.getId() == null) { + // something went wrong and we're not sure what so delete pNode + if (pNode.getId() != null) { + dao.delete(pNode); + } + throw new RuntimeException("Metadata didn't save, node was removed: "+pNode); + } else if (pNode.getId() == null) { + // something went wrong and we're not sure what so delete metadata + if (metaData.getId() != null) { + dao.delete(metaData); + } + throw new RuntimeException("Metadata didn't save, metaData was removed: "+metaData); + } else if (!metaData.getId().equals(pNode.getId())) { + // the indexes are off... let's try to get them back in sync + int i = 0; + if (pNode.getId() > metaData.getId()) { + while (i < 100 && metaData.getId() != null && pNode.getId() != metaData.getId()) { + // need to keep saving metaData until it's sequence has caught up + dao.delete(metaData); + // set ID back to null to make it save with a new incremented ID + metaData.setId(null); + dao.save(metaData); + i++; + } + } else { + while (i < 100 && pNode.getId() != null && pNode.getId() != metaData.getId()) { + // need to keep saving node until it's sequence has caught up + dao.delete(pNode); + // set ID back to null to make it save with a new incremented ID + pNode.setId(null); + dao.save(pNode); + i++; + } + } + if (pNode.getId() == null || metaData.getId() == null || pNode.getId() != metaData.getId()) { + // ok we tried, it didn't work, so throw the exception + throw new RuntimeException("Node ID: " + pNode.getId() + " doesn't match Metadata ID: " + metaData.getId()); + } + } + } + + /** + * Fetch node data from storage + * + * @param nodeId + * @return a {@link HierarchyNodeMetaData} or null if not found + */ + private HierarchyNodeMetaData getNodeMeta(String nodeId) { + List l = dao.findBySearch(HierarchyNodeMetaData.class, + new Search("node.id", new Long(nodeId))); + if (l.size() > 1) { + throw new IllegalStateException("Invalid hierarchy state: more than one node with id: " + nodeId); + } else if (l.size() == 1) { + return l.get(0); + } else { + return null; + } + } + + /** + * Find the current root node + * + * @param hierarchyId + * @return the root {@link HierarchyNodeMetaData} of the hierarchy + */ + private HierarchyNodeMetaData getRootNodeMetaByHierarchy(String hierarchyId) { + List l = dao.findBySearch(HierarchyNodeMetaData.class, + new Search(new Restriction[] { + new Restriction("hierarchyId", hierarchyId), + new Restriction("isRootNode", Boolean.TRUE) + }) ); + if (l.size() > 1) { + throw new IllegalStateException("Invalid hierarchy state: more than one root node for hierarchyId: " + + hierarchyId); + } else if (l.size() == 1) { + return l.get(0); + } else { + return null; + } + } + + /** + * Get all nodes and meta data based on a set of nodeIds + * + * @param nodeIds + * @return + */ + private List getNodeMetas(Set nodeIds) { + return getNodeMetas(nodeIds.toArray(new String[] {})); + } + + private List getNodeMetas(String[] nodeIds) { + List l = null; + if (nodeIds == null || nodeIds.length == 0) { + l = new ArrayList(); + } else { + Long[] pNodeIds = new Long[nodeIds.length]; + for (int i = 0; i < nodeIds.length; i++) { + pNodeIds[i] = new Long(nodeIds[i]); + } + l = new ArrayList(); + List nodeIdsList = new ArrayList(Arrays.asList(pNodeIds)); + int i = 0; + do{ + int arraySize = nodeIdsList.size() - i; + if(oracle && arraySize > ORACLE_IN_CLAUSE_SIZE_LIMIT){ + arraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT; + } + List lIterration = dao.findBySearch(HierarchyNodeMetaData.class, + new Search("node.id", nodeIdsList.subList(i, i + arraySize).toArray()) ); + l.addAll(lIterration); + i += arraySize; + }while(i < nodeIdsList.size()); + } + return l; + } + + /** + * Get all nodes only based on a set of nodeIds + * + * @param nodeIds + * @return + */ + private List getNodes(Set nodeIds) { + return getNodes(nodeIds.toArray(new String[] {})); + } + + private List getNodes(String[] nodeIds) { + List l = null; + if (nodeIds == null || nodeIds.length == 0) { + l = new ArrayList(); + } else { + Long[] pNodeIds = new Long[nodeIds.length]; + for (int i = 0; i < nodeIds.length; i++) { + pNodeIds[i] = new Long(nodeIds[i]); + } + l = new ArrayList(); + List nodeIdsList = new ArrayList(Arrays.asList(pNodeIds)); + int i = 0; + do{ + int arraySize = nodeIdsList.size() - i; + if(oracle && arraySize > ORACLE_IN_CLAUSE_SIZE_LIMIT){ + arraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT; + } + List lIterration = dao.findBySearch(HierarchyPersistentNode.class, + new Search("id", nodeIdsList.subList(i, i + arraySize).toArray()) ); + l.addAll(lIterration); + i += arraySize; + }while(i < nodeIdsList.size()); + } + return l; + } + + /** + * Find the direct parent node id for a node + * @param node + * @return the node if or null if none exists + */ + private String getParentNodeId(HierarchyNode node) { + String parentNodeId = null; + if (node.directParentNodeIds != null && + node.directParentNodeIds.size() > 0) { + parentNodeId = node.directParentNodeIds.iterator().next(); + } + return parentNodeId; + } + +} diff --git a/hierarchy/impl/src/java/org/sakaiproject/hierarchy/impl/utils/HierarchyImplUtils.java b/hierarchy/impl/src/java/org/sakaiproject/hierarchy/impl/utils/HierarchyImplUtils.java new file mode 100644 index 000000000000..acaa44a13d2b --- /dev/null +++ b/hierarchy/impl/src/java/org/sakaiproject/hierarchy/impl/utils/HierarchyImplUtils.java @@ -0,0 +1,187 @@ +/* +* Licensed to The Apereo Foundation under one or more contributor license +* agreements. See the NOTICE file distributed with this work for +* additional information regarding copyright ownership. +* +* The Apereo Foundation licenses this file to you under the Educational +* Community License, Version 2.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of the +* License at: +* +* http://opensource.org/licenses/ecl2.txt +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.sakaiproject.hierarchy.impl.utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.sakaiproject.hierarchy.dao.model.HierarchyNodeMetaData; +import org.sakaiproject.hierarchy.dao.model.HierarchyPersistentNode; +import org.sakaiproject.hierarchy.model.HierarchyNode; + +/** + * Utility class for the hierarchy service + * + * @author Aaron Zeckoski (aaronz@vt.edu) + */ +public class HierarchyImplUtils { + + public static final char SEPERATOR = ':'; + + /** + * Create a {@link HierarchyNode} from the persistent data, + * exception if the data is not persisted or data is missing + * @param pNode a {@link HierarchyPersistentNode} which has been persisted + * @param metaData a {@link HierarchyNodeMetaData} which has been persisted + * @return a {@link HierarchyNode} which contains data from the 2 inputs + */ + public static HierarchyNode makeNode(HierarchyPersistentNode pNode, HierarchyNodeMetaData metaData) { + if (pNode == null || pNode.getId() == null) { + throw new IllegalArgumentException("pNode cannot be null and id of pNode must be set"); + } + + HierarchyNode hNode = new HierarchyNode(); + hNode.id = pNode.getId().toString(); + + hNode.directParentNodeIds = makeNodeIdSet(pNode.getDirectParentIds()); + hNode.parentNodeIds = makeNodeIdSet(pNode.getParentIds()); + hNode.directChildNodeIds = makeNodeIdSet(pNode.getDirectChildIds()); + hNode.childNodeIds = makeNodeIdSet(pNode.getChildIds()); + + hNode.hierarchyId = metaData.getHierarchyId(); + hNode.title = metaData.getTitle(); + hNode.description = metaData.getDescription(); + hNode.permToken = metaData.getPermToken(); + hNode.isDisabled = metaData.getIsDisabled(); + + return hNode; + } + + /** + * Convenience method to create a user-facing node object from a combination metaData/Node object, + * will return back a null if given a null + * @param metaData a {@link HierarchyNodeMetaData} which has been persisted and contains a {@link HierarchyPersistentNode} + * @return a {@link HierarchyNode} which contains data from the persistent object + */ + public static HierarchyNode makeNode(HierarchyNodeMetaData metaData) { + if (metaData == null) { return null; } + if (metaData.getNode() == null || + metaData.getNode().getId() == null) { + throw new IllegalArgumentException("Invalid metaData object: Must contain a complete HierarchyPersistentNode object"); + } + return makeNode(metaData.getNode(), metaData); + } + + /** + * Make a Set of node Ids from an encoded string of nodeIds, + * will not throw exception or return null + * @param encodedNodeIds an encoded string of nodeIds + * @return a {@link Set} with the nodeIds in it, ordered by nodeId + */ + public static Set makeNodeIdSet(String encodedNodeIds) { + Set s = new TreeSet(); + if (encodedNodeIds != null) { + String[] split = encodedNodeIds.split( String.valueOf(SEPERATOR) ); + if (split.length > 0) { + for (int i = 0; i < split.length; i++) { + if (split[i] != null && !split[i].equals("")) { + s.add(split[i]); + } + } + } + } + return s; + } + + /** + * Make an encoded string of nodeIds from a Set of nodeIds + * @param nodeIds a {@link Set} with the nodeIds in it + * @return an encoded string of nodeIds + */ + public static String makeEncodedNodeIdString(Set nodeIds) { + if (nodeIds == null || nodeIds.size() <= 0) { + return null; + } + // make sure the order written into the database is natural node order + List l = new ArrayList(nodeIds); + Collections.sort(l); + // encode the string + StringBuilder coded = new StringBuilder(); + coded.append(HierarchyImplUtils.SEPERATOR); + for (String nodeId : l) { + coded.append(nodeId); + coded.append(HierarchyImplUtils.SEPERATOR); + } + return coded.toString(); + } + + /** + * Method to allow us to easily build an encoded string for a single node without having to create a set first + * @param nodeId unique id string for a node + * @return an encoded string of nodeIds + */ + public static String makeSingleEncodedNodeIdString(String nodeId) { + if (nodeId == null || nodeId.length() == 0) { + return null; + } + return HierarchyImplUtils.SEPERATOR + nodeId + HierarchyImplUtils.SEPERATOR; + } + + /** + * Method to allows us to add a single nodeId to an encoded string of nodeIds without creating a set, + * will maintain the correct order for nodeIds, + * (do not run this over and over, use a set if you need to add more than one node) + * @param encodedNodeIds an encoded string of nodeIds + * @param nodeId unique id string for a node + * @return an encoded string of nodeIds + */ + public static String addSingleNodeIdToEncodedString(String encodedNodeIds, String nodeId) { + if (encodedNodeIds == null || encodedNodeIds.length() == 0) { + return makeSingleEncodedNodeIdString(nodeId); + } + if (nodeId == null || nodeId.length() == 0) { + return encodedNodeIds; + } + if (encodedNodeIds.indexOf(makeSingleEncodedNodeIdString(nodeId)) != -1) { + // this nodeId is already in the encoded string + return encodedNodeIds; + } + int thisSeparator = 0; + int lastIndex = encodedNodeIds.length()-1; + while (thisSeparator < lastIndex ) { + int nextSeparator = encodedNodeIds.indexOf(HierarchyImplUtils.SEPERATOR, thisSeparator+1); + String thisNodeId = encodedNodeIds.substring(thisSeparator+1, nextSeparator); + if (thisNodeId.compareTo(nodeId) > 0) { + // thisNodeId comes after nodeId + break; + } else { + thisSeparator = nextSeparator; + } + } + + String newEncodedNodeIds = null; + if (thisSeparator == 0) { + // put the node at the front of the string + newEncodedNodeIds = HierarchyImplUtils.SEPERATOR + nodeId + encodedNodeIds; + } else if (thisSeparator == lastIndex) { + // put node at the end + newEncodedNodeIds = encodedNodeIds + nodeId + HierarchyImplUtils.SEPERATOR; + } else { + // put the node at the location indicated by thisSeparator + newEncodedNodeIds = encodedNodeIds.substring(0, thisSeparator) + + HierarchyImplUtils.SEPERATOR + nodeId + encodedNodeIds.substring(thisSeparator); + } + return newEncodedNodeIds; + } + +} diff --git a/hierarchy/impl/src/test/hibernate-test.xml b/hierarchy/impl/src/test/hibernate-test.xml new file mode 100644 index 000000000000..8940d6944321 --- /dev/null +++ b/hierarchy/impl/src/test/hibernate-test.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + classpath:/hibernate.properties + + + + + + + ${hibernate.connection.driver_class} + ${hibernate.connection.url} + ${hibernate.connection.username} + ${hibernate.connection.password} + + + + + + + + + ${hibernate.dialect} + ${hibernate.show_sql} + ${hibernate.cache.provider_class} + true 1, false 0 + ${hibernate.hbm2ddl.auto} + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hierarchy/impl/src/test/hibernate.properties b/hierarchy/impl/src/test/hibernate.properties new file mode 100644 index 000000000000..52e75d619dad --- /dev/null +++ b/hierarchy/impl/src/test/hibernate.properties @@ -0,0 +1,17 @@ +# This file generated by Sakai App Builder -AZ +# This properties file defines the connection to the HSQLDB database +hibernate.connection.driver_class=org.hsqldb.jdbcDriver +hibernate.dialect=org.hibernate.dialect.HSQLDialect + +hibernate.connection.url=jdbc:hsqldb:. +hibernate.connection.username=sa +hibernate.connection.password= + +#hibernate.show_sql=true +hibernate.show_sql=false +hibernate.hbm2ddl.auto=create +hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider + +# Needed for Hibernate 3 if you are using old HQL syntax +# (you have to in Sakai 2.2.x or lower) -AZ +# hibernate.query.factory_class=org.hibernate.hql.classic.ClassicQueryTranslatorFactory diff --git a/hierarchy/impl/src/test/org/sakaiproject/hierarchy/impl/test/HierarchyImplUtilsTest.java b/hierarchy/impl/src/test/org/sakaiproject/hierarchy/impl/test/HierarchyImplUtilsTest.java new file mode 100644 index 000000000000..eda06630f47a --- /dev/null +++ b/hierarchy/impl/src/test/org/sakaiproject/hierarchy/impl/test/HierarchyImplUtilsTest.java @@ -0,0 +1,231 @@ +/****************************************************************************** + * HierarchyUtilsTest.java - created by aaronz on Jul 31, 2007 + * + * Copyright (c) 2007 Centre for Academic Research in Educational Technologies + * Licensed under the Educational Community License version 1.0 + * + * A copy of the Educational Community License has been included in this + * distribution and is available at: http://www.opensource.org/licenses/ecl1.php + * + *****************************************************************************/ + +package org.sakaiproject.hierarchy.impl.test; + +import java.util.HashSet; +import java.util.Set; + +import junit.framework.TestCase; + +import org.sakaiproject.hierarchy.dao.model.HierarchyNodeMetaData; +import org.sakaiproject.hierarchy.dao.model.HierarchyPersistentNode; +import org.sakaiproject.hierarchy.impl.utils.HierarchyImplUtils; +import org.sakaiproject.hierarchy.model.HierarchyNode; + +/** + * Testing the utils class to make sure we can count on it + * + * @author Aaron Zeckoski (aaronz@vt.edu) + */ +public class HierarchyImplUtilsTest extends TestCase { + + private char s = HierarchyImplUtils.SEPERATOR; + + private String NODE1 = "1"; + private String NODE2 = "2"; + private String NODE3 = "3"; + private String NODE30 = "30"; + private String NODE41 = "41"; + private String NODE42 = "42"; + private String NODE50 = "50"; + + private String ENCODED_NODE1 = s + NODE1 + s; + + private String ENCODED_1 = s + NODE1 + s + NODE3 + s + NODE30 + s; + private String ENCODED_2 = s + NODE2 + s + NODE30 + s + NODE41 + s + NODE50 + s; + private String ENCODED_3 = s + NODE30 + s + NODE42 + s; + + private String ENCODED_1_41 = ENCODED_1 + NODE41 + s; + private String ENCODED_2_1 = s + NODE1 + ENCODED_2; + private String ENCODED_3_41 = s + NODE30 + s + NODE41 + s + NODE42 + s; + + /* (non-Javadoc) + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + super.setUp(); + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.utils.HierarchyImplUtils#makeNode(org.sakaiproject.hierarchy.dao.model.HierarchyPersistentNode, org.sakaiproject.hierarchy.dao.model.HierarchyNodeMetaData)}. + */ + public void testMakeNodeHierarchyPersistentNodeHierarchyNodeMetaData() { + HierarchyNode node = null; + + HierarchyNodeMetaData metaData = new HierarchyNodeMetaData(null, "HID", Boolean.FALSE, "aaronz", "Title", "Desc", "KEY", Boolean.FALSE); + HierarchyPersistentNode pNode = new HierarchyPersistentNode(ENCODED_NODE1, ENCODED_1); + pNode.setId( new Long(100) ); + + node = HierarchyImplUtils.makeNode(pNode, metaData); + assertNotNull(node); + assertEquals("100", node.id); + assertEquals("HID", node.hierarchyId); + assertEquals("Title", node.title); + assertEquals("Desc", node.description); + assertEquals("KEY", node.permToken); + assertNotNull(node.directParentNodeIds); + assertTrue(node.directParentNodeIds.contains(NODE1)); + assertNotNull(node.parentNodeIds); + assertTrue(node.parentNodeIds.contains(NODE1)); + assertTrue(node.parentNodeIds.contains(NODE3)); + assertNotNull(node.directChildNodeIds); + assertTrue(node.directChildNodeIds.isEmpty()); + assertNotNull(node.childNodeIds); + assertTrue(node.childNodeIds.isEmpty()); + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.utils.HierarchyImplUtils#makeNode(org.sakaiproject.hierarchy.dao.model.HierarchyNodeMetaData)}. + */ + public void testMakeNodeHierarchyNodeMetaData() { + HierarchyNode node = null; + + // test that null meta causes null + node = HierarchyImplUtils.makeNode(null); + assertNull(node); + + HierarchyPersistentNode pNode = null; + HierarchyNodeMetaData metaData = new HierarchyNodeMetaData(pNode, "HID", Boolean.FALSE, "aaronz", "Title", "Desc", null, Boolean.FALSE); + + // test that invalid pNode causes death + try { + node = HierarchyImplUtils.makeNode(metaData); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e); + } + + pNode = new HierarchyPersistentNode(ENCODED_NODE1, ENCODED_1); + pNode.setId( new Long(100) ); + metaData.setNode(pNode); + node = HierarchyImplUtils.makeNode(metaData); + assertNotNull(node); + assertEquals("100", node.id); + assertEquals("HID", node.hierarchyId); + assertEquals("Title", node.title); + assertEquals("Desc", node.description); + assertNotNull(node.directParentNodeIds); + assertTrue(node.directParentNodeIds.contains(NODE1)); + assertNotNull(node.parentNodeIds); + assertTrue(node.parentNodeIds.contains(NODE1)); + assertTrue(node.parentNodeIds.contains(NODE3)); + assertNotNull(node.directChildNodeIds); + assertTrue(node.directChildNodeIds.isEmpty()); + assertNotNull(node.childNodeIds); + assertTrue(node.childNodeIds.isEmpty()); + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.utils.HierarchyImplUtils#makeNodeIdSet(java.lang.String)}. + */ + public void testMakeNodeIdSet() { + Set nodeIds = null; + + nodeIds = HierarchyImplUtils.makeNodeIdSet(null); + assertNotNull(nodeIds); + assertTrue(nodeIds.isEmpty()); + + nodeIds = HierarchyImplUtils.makeNodeIdSet(ENCODED_1); + assertNotNull(nodeIds); + assertEquals(3, nodeIds.size()); + assertTrue(nodeIds.contains(NODE1)); + assertTrue(nodeIds.contains(NODE3)); + assertTrue(nodeIds.contains(NODE30)); + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.utils.HierarchyImplUtils#makeEncodedNodeIdString(java.util.Set)}. + */ + public void testMakeEncodedNodeIdString() { + String encoded = null; + + Set nodeIds = new HashSet(); + + // check that empty set generates null string + encoded = HierarchyImplUtils.makeEncodedNodeIdString(nodeIds); + assertNull(encoded); + + nodeIds.add(NODE1); + nodeIds.add(NODE30); + nodeIds.add(NODE3); + + // test converting set to string + encoded = HierarchyImplUtils.makeEncodedNodeIdString(nodeIds); + assertNotNull(encoded); + assertEquals(ENCODED_1, encoded); + + nodeIds.add(NODE41); + + // test converting set to string + encoded = HierarchyImplUtils.makeEncodedNodeIdString(nodeIds); + assertNotNull(encoded); + assertEquals(ENCODED_1_41, encoded); + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.utils.HierarchyImplUtils#makeSingleEncodedNodeIdString(java.lang.String)}. + */ + public void testMakeSingleEncodedNodeIdString() { + String encoded = null; + + // encoding a string + encoded = HierarchyImplUtils.makeSingleEncodedNodeIdString(NODE1); + assertNotNull(encoded); + assertEquals(ENCODED_NODE1, encoded); + + encoded = HierarchyImplUtils.makeSingleEncodedNodeIdString(null); + assertNull(encoded); + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.utils.HierarchyImplUtils#addSingleNodeIdToEncodedString(java.lang.String, java.lang.String)}. + */ + public void testAddSingleNodeIdToEncodedString() { + String encoded = null; + + // try adding strings to various points in the encoded string + encoded = HierarchyImplUtils.addSingleNodeIdToEncodedString(ENCODED_2, NODE1); + assertNotNull(encoded); + assertEquals(ENCODED_2_1, encoded); + + encoded = HierarchyImplUtils.addSingleNodeIdToEncodedString(ENCODED_3, NODE41); + assertNotNull(encoded); + assertEquals(ENCODED_3_41, encoded); + + encoded = HierarchyImplUtils.addSingleNodeIdToEncodedString(ENCODED_1, NODE41); + assertNotNull(encoded); + assertEquals(ENCODED_1_41, encoded); + + // try adding string that already exist + encoded = HierarchyImplUtils.addSingleNodeIdToEncodedString(ENCODED_1, NODE3); + assertNotNull(encoded); + assertEquals(ENCODED_1, encoded); + + encoded = HierarchyImplUtils.addSingleNodeIdToEncodedString(ENCODED_2, NODE2); + assertNotNull(encoded); + assertEquals(ENCODED_2, encoded); + + encoded = HierarchyImplUtils.addSingleNodeIdToEncodedString(ENCODED_3, NODE42); + assertNotNull(encoded); + assertEquals(ENCODED_3, encoded); + + // now try out the edge cases + encoded = HierarchyImplUtils.addSingleNodeIdToEncodedString(null, NODE1); + assertNotNull(encoded); + assertEquals(ENCODED_NODE1, encoded); + + encoded = HierarchyImplUtils.addSingleNodeIdToEncodedString(ENCODED_1, null); + assertNotNull(encoded); + assertEquals(ENCODED_1, encoded); + } + +} diff --git a/hierarchy/impl/src/test/org/sakaiproject/hierarchy/impl/test/HierarchyServiceImplTest.java b/hierarchy/impl/src/test/org/sakaiproject/hierarchy/impl/test/HierarchyServiceImplTest.java new file mode 100644 index 000000000000..395acba16c5e --- /dev/null +++ b/hierarchy/impl/src/test/org/sakaiproject/hierarchy/impl/test/HierarchyServiceImplTest.java @@ -0,0 +1,1645 @@ +/****************************************************************************** + * HierarchyServiceImplTest.java - created by aaronz on Jul 1, 2007 + * + * Copyright (c) 2007 Centre for Academic Research in Educational Technologies + * Licensed under the Educational Community License version 1.0 + * + * A copy of the Educational Community License has been included in this + * distribution and is available at: http://www.opensource.org/licenses/ecl1.php + * + *****************************************************************************/ + +package org.sakaiproject.hierarchy.impl.test; + +import java.util.Map; +import java.util.Set; + +import org.sakaiproject.genericdao.api.search.Search; +import org.sakaiproject.hierarchy.dao.HierarchyDao; +import org.sakaiproject.hierarchy.dao.model.HierarchyNodeMetaData; +import org.sakaiproject.hierarchy.impl.HierarchyServiceImpl; +import org.sakaiproject.hierarchy.impl.test.data.TestDataPreload; +import org.sakaiproject.hierarchy.model.HierarchyNode; +import org.springframework.test.AbstractTransactionalSpringContextTests; + +/** + * Testing the hierarchy service + * + * @author Aaron Zeckoski (aaronz@vt.edu) + */ +public class HierarchyServiceImplTest extends AbstractTransactionalSpringContextTests { + + protected HierarchyServiceImpl hierarchyService; + + private HierarchyDao dao; + private TestDataPreload tdp; + + // private SessionManager sessionManager; + // private MockControl sessionManagerControl; + + + protected String[] getConfigLocations() { + // point to the needed spring config files, must be on the classpath + // (add component/src/webapp/WEB-INF to the build path in Eclipse), + // they also need to be referenced in the project.xml file + return new String[] {"hibernate-test.xml", "spring-hibernate.xml"}; + } + + // run this before each test starts + protected void onSetUpBeforeTransaction() throws Exception { + // load the spring created dao class bean from the Spring Application Context + dao = (HierarchyDao) applicationContext.getBean("org.sakaiproject.hierarchy.dao.HierarchyDao"); + if (dao == null) { + throw new NullPointerException("Dao could not be retrieved from spring context"); + } + + // load up the test data preloader from spring + tdp = (TestDataPreload) applicationContext.getBean("org.sakaiproject.hierarchy.test.data.TestDataPreload"); + if (tdp == null) { + throw new NullPointerException("TestDatePreload could not be retrieved from spring context"); + } + + // load up any other needed spring beans + + // // setup the mock objects if needed + // sessionManagerControl = MockControl.createControl(SessionManager.class); + // sessionManager = (SessionManager) sessionManagerControl.getMock(); + + // //this mock object is simply keeping us from getting a null when getCurrentSessionUserId is called + // sessionManager.getCurrentSessionUserId(); // expect this to be called + // sessionManagerControl.setDefaultMatcher(MockControl.ALWAYS_MATCHER); + // sessionManagerControl.setReturnValue(TestDataPreload.USER_ID, MockControl.ZERO_OR_MORE); + // sessionManagerControl.replay(); + + //create and setup the object to be tested + hierarchyService = new HierarchyServiceImpl(); + hierarchyService.setDao(dao); + // hierarchyService.setSessionManager(sessionManager); + } + + // run this before each test starts and as part of the transaction + protected void onSetUpInTransaction() { + // preload additional data if desired + } + + /** + * ADD unit tests below here, use testMethod as the name of the unit test, + * Note that if a method is overloaded you should include the arguments in the + * test name like so: testMethodClassInt (for method(Class, int); + */ + + public void testValidTestData() { + // ensure the test data is setup the way we think + assertEquals(new Long(1), tdp.pNode1.getId()); + assertEquals(new Long(6), tdp.pNode6.getId()); + assertEquals(new Long(9), tdp.pNode9.getId()); + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#createHierarchy(java.lang.String)}. + */ + public void testCreateHierarchy() { + // test creating a valid hierarchy + HierarchyNode node = hierarchyService.createHierarchy("hierarchyC"); + assertNotNull(node); + assertEquals("hierarchyC", node.hierarchyId); + assertNotNull(node.parentNodeIds); + assertNotNull(node.childNodeIds); + assertTrue(node.parentNodeIds.isEmpty()); + assertTrue(node.childNodeIds.isEmpty()); + + // test creating a hierarchy that already exists + try { + hierarchyService.createHierarchy(TestDataPreload.HIERARCHYA); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e); + } + + // test creating a hierarchy with too long an id + try { + hierarchyService.createHierarchy("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e); + } + + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#setHierarchyRootNode(java.lang.String, java.lang.String)}. + */ + public void testSetHierarchyRootNode() { + HierarchyNode node = null; + + // test reassigning existing rootnode is no problem + node = hierarchyService.setHierarchyRootNode(TestDataPreload.HIERARCHYA, tdp.node1.id); + assertNotNull(node); + assertEquals(TestDataPreload.HIERARCHYA, node.hierarchyId); + assertEquals(tdp.node1.id, node.id); + + // test reassigning a new node to be the parent node + assertEquals(Boolean.FALSE, tdp.meta11.getIsRootNode()); + assertEquals(Boolean.TRUE, tdp.meta9.getIsRootNode()); + node = hierarchyService.setHierarchyRootNode(TestDataPreload.HIERARCHYB, tdp.node11.id); + assertNotNull(node); + assertEquals(TestDataPreload.HIERARCHYB, node.hierarchyId); + assertEquals(tdp.node11.id, node.id); + + // test assigning a node which has parents causes failure + try { + hierarchyService.setHierarchyRootNode(TestDataPreload.HIERARCHYA, tdp.node3.id); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e); + } + + // test assigning a root node from another hierarchy to this root causes failure + try { + hierarchyService.setHierarchyRootNode(TestDataPreload.HIERARCHYB, tdp.node1.id); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e); + } + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#destroyHierarchy(java.lang.String)}. + */ + public void testDestroyHierarchy() { + hierarchyService.destroyHierarchy(TestDataPreload.HIERARCHYB); + long count = dao.countBySearch(HierarchyNodeMetaData.class, + new Search("hierarchyId", TestDataPreload.HIERARCHYB) ); + assertEquals(0, count); + + // test removing a non-existent hierarchy fails + try { + hierarchyService.destroyHierarchy(TestDataPreload.HIERARCHYB); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e); + } + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#getRootLevelNode(java.lang.String)}. + */ + public void testGetRootLevelNode() { + HierarchyNode node = null; + + node = hierarchyService.getRootNode(TestDataPreload.HIERARCHYB); + assertNotNull(node); + assertEquals(tdp.node9, node); + assertEquals(TestDataPreload.HIERARCHYB, node.hierarchyId); + + node = hierarchyService.getRootNode(TestDataPreload.HIERARCHYA); + assertNotNull(node); + assertEquals(tdp.node1, node); + assertEquals(TestDataPreload.HIERARCHYA, node.hierarchyId); + + // fetching root from invalid hierarchy gets null + node = hierarchyService.getRootNode(TestDataPreload.INVALID_HIERARCHY); + assertNull(node); + + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#getNodeById(java.lang.String)}. + */ + public void testGetNodeById() { + HierarchyNode node = null; + + node = hierarchyService.getNodeById(tdp.node4.id); + assertNotNull(node); + assertEquals(tdp.node4, node); + assertEquals(tdp.node4.id, node.id); + + node = hierarchyService.getNodeById(tdp.node6.id); + assertNotNull(node); + assertEquals(tdp.node6, node); + assertEquals(tdp.node6.id, node.id); + + // fetching node with invalid id should fail + try { + node = hierarchyService.getNodeById(TestDataPreload.INVALID_NODE_ID); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e); + } + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#getChildNodes(java.lang.String, boolean)}. + */ + public void testGetChildNodes() { + Set nodes; + + // check children for the root + nodes = hierarchyService.getChildNodes(tdp.node1.id, true); + assertNotNull(nodes); + assertEquals(3, nodes.size()); + assertTrue(nodes.contains(tdp.node2)); + assertTrue(nodes.contains(tdp.node3)); + assertTrue(nodes.contains(tdp.node4)); + + nodes = hierarchyService.getChildNodes(tdp.node1.id, false); + assertNotNull(nodes); + assertEquals(7, nodes.size()); + assertTrue(nodes.contains(tdp.node2)); + assertTrue(nodes.contains(tdp.node3)); + assertTrue(nodes.contains(tdp.node4)); + assertTrue(nodes.contains(tdp.node5)); + assertTrue(nodes.contains(tdp.node6)); + assertTrue(nodes.contains(tdp.node7)); + assertTrue(nodes.contains(tdp.node8)); + + // check children for the mid level nodes + nodes = hierarchyService.getChildNodes(tdp.node4.id, true); + assertNotNull(nodes); + assertEquals(3, nodes.size()); + assertTrue(nodes.contains(tdp.node6)); + assertTrue(nodes.contains(tdp.node7)); + assertTrue(nodes.contains(tdp.node8)); + + nodes = hierarchyService.getChildNodes(tdp.node4.id, false); + assertNotNull(nodes); + assertEquals(3, nodes.size()); + assertTrue(nodes.contains(tdp.node6)); + assertTrue(nodes.contains(tdp.node7)); + assertTrue(nodes.contains(tdp.node8)); + + // leaf nodes have no children + nodes = hierarchyService.getChildNodes(tdp.node5.id, true); + assertNotNull(nodes); + assertEquals(0, nodes.size()); + + nodes = hierarchyService.getChildNodes(tdp.node7.id, true); + assertNotNull(nodes); + assertEquals(0, nodes.size()); + + // fetching children for invalid node id should fail + try { + nodes = hierarchyService.getChildNodes(TestDataPreload.INVALID_NODE_ID, true); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e); + } + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#getParentNodes(java.lang.String, boolean)}. + */ + public void testGetParentNodes() { + Set nodes; + + // check parents for leaf nodes first + nodes = hierarchyService.getParentNodes(tdp.node7.id, false); + assertNotNull(nodes); + assertEquals(2, nodes.size()); + assertTrue(nodes.contains(tdp.node1)); + assertTrue(nodes.contains(tdp.node4)); + + nodes = hierarchyService.getParentNodes(tdp.node7.id, true); + assertNotNull(nodes); + assertEquals(1, nodes.size()); + assertTrue(nodes.contains(tdp.node4)); + + nodes = hierarchyService.getParentNodes(tdp.node5.id, false); + assertNotNull(nodes); + assertEquals(2, nodes.size()); + assertTrue(nodes.contains(tdp.node1)); + assertTrue(nodes.contains(tdp.node3)); + + // check one with multiple parents + nodes = hierarchyService.getParentNodes(tdp.node10.id, false); + assertNotNull(nodes); + assertEquals(2, nodes.size()); + assertTrue(nodes.contains(tdp.node9)); + assertTrue(nodes.contains(tdp.node11)); + + nodes = hierarchyService.getParentNodes(tdp.node10.id, true); + assertNotNull(nodes); + assertEquals(2, nodes.size()); + assertTrue(nodes.contains(tdp.node9)); + assertTrue(nodes.contains(tdp.node11)); + + // root nodes have no parents + nodes = hierarchyService.getParentNodes(tdp.node1.id, true); + assertNotNull(nodes); + assertEquals(0, nodes.size()); + + nodes = hierarchyService.getParentNodes(tdp.node9.id, true); + assertNotNull(nodes); + assertEquals(0, nodes.size()); + + // fetching children for invalid node id should fail + try { + nodes = hierarchyService.getParentNodes(TestDataPreload.INVALID_NODE_ID, true); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e); + } + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#addNode(java.lang.String, java.lang.String)}. + */ + public void testAddNode() { + HierarchyNode node = null; + String newNodeId = null; + + // check we can insert a node in a normal tree and that the links are created correctly in this node + node = hierarchyService.addNode(TestDataPreload.HIERARCHYA, tdp.node2.id); + assertNotNull(node); + newNodeId = node.id; + assertNotNull(newNodeId); + assertNotNull(node.directParentNodeIds); + assertEquals(1, node.directParentNodeIds.size()); + assertTrue(node.directParentNodeIds.contains(tdp.node2.id)); + assertNotNull(node.parentNodeIds); + assertEquals(2, node.parentNodeIds.size()); + assertTrue(node.parentNodeIds.contains(tdp.node2.id)); + assertTrue(node.parentNodeIds.contains(tdp.node1.id)); + assertNotNull(node.directChildNodeIds); + assertTrue(node.directChildNodeIds.isEmpty()); + assertNotNull(node.childNodeIds); + assertTrue(node.childNodeIds.isEmpty()); + + // now check that the child links were updated correctly for the parent + node = hierarchyService.getNodeById(tdp.node2.id); + assertNotNull(node); + assertEquals(tdp.node2.id, node.id); + assertNotNull(node.directChildNodeIds); + assertEquals(1, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(newNodeId)); + assertNotNull(node.childNodeIds); + assertEquals(1, node.childNodeIds.size()); + assertTrue(node.childNodeIds.contains(newNodeId)); + + // and the root node + node = hierarchyService.getNodeById(tdp.node1.id); + assertNotNull(node); + assertEquals(tdp.node1.id, node.id); + assertNotNull(node.directChildNodeIds); + assertEquals(3, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(tdp.node2.id)); + assertTrue(node.directChildNodeIds.contains(tdp.node3.id)); + assertTrue(node.directChildNodeIds.contains(tdp.node4.id)); + assertNotNull(node.childNodeIds); + assertEquals(8, node.childNodeIds.size()); + assertTrue(node.childNodeIds.contains(newNodeId)); + assertTrue(node.childNodeIds.contains(tdp.node2.id)); + assertTrue(node.childNodeIds.contains(tdp.node3.id)); + assertTrue(node.childNodeIds.contains(tdp.node4.id)); + assertTrue(node.childNodeIds.contains(tdp.node5.id)); + assertTrue(node.childNodeIds.contains(tdp.node6.id)); + assertTrue(node.childNodeIds.contains(tdp.node7.id)); + assertTrue(node.childNodeIds.contains(tdp.node8.id)); + + + // check we can insert a node in an upward tree and that the links are created correctly in this node + node = hierarchyService.addNode(TestDataPreload.HIERARCHYB, tdp.node10.id); + assertNotNull(node); + newNodeId = node.id; + assertNotNull(newNodeId); + assertNotNull(node.directParentNodeIds); + assertEquals(1, node.directParentNodeIds.size()); + assertTrue(node.directParentNodeIds.contains(tdp.node10.id)); + assertNotNull(node.parentNodeIds); + assertEquals(3, node.parentNodeIds.size()); + assertTrue(node.parentNodeIds.contains(tdp.node10.id)); + assertTrue(node.parentNodeIds.contains(tdp.node9.id)); + assertTrue(node.parentNodeIds.contains(tdp.node11.id)); + assertNotNull(node.directChildNodeIds); + assertTrue(node.directChildNodeIds.isEmpty()); + assertNotNull(node.childNodeIds); + assertTrue(node.childNodeIds.isEmpty()); + + // now check that the child links were updated correctly for the parent + node = hierarchyService.getNodeById(tdp.node10.id); + assertNotNull(node); + assertEquals(tdp.node10.id, node.id); + assertNotNull(node.directChildNodeIds); + assertEquals(1, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(newNodeId)); + assertNotNull(node.childNodeIds); + assertEquals(1, node.childNodeIds.size()); + assertTrue(node.childNodeIds.contains(newNodeId)); + + // and the root node + node = hierarchyService.getNodeById(tdp.node9.id); + assertNotNull(node); + assertEquals(tdp.node9.id, node.id); + assertNotNull(node.directChildNodeIds); + assertEquals(1, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(tdp.node10.id)); + assertNotNull(node.childNodeIds); + assertEquals(2, node.childNodeIds.size()); + assertTrue(node.childNodeIds.contains(newNodeId)); + assertTrue(node.childNodeIds.contains(tdp.node10.id)); + + // and the other higher parent node + node = hierarchyService.getNodeById(tdp.node11.id); + assertNotNull(node); + assertEquals(tdp.node11.id, node.id); + assertNotNull(node.directChildNodeIds); + assertEquals(1, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(tdp.node10.id)); + assertNotNull(node.childNodeIds); + assertEquals(2, node.childNodeIds.size()); + assertTrue(node.childNodeIds.contains(newNodeId)); + assertTrue(node.childNodeIds.contains(tdp.node10.id)); + + + // check we can insert a node next to others and that the links are created correctly in this node + node = hierarchyService.addNode(TestDataPreload.HIERARCHYA, tdp.node3.id); + assertNotNull(node); + newNodeId = node.id; + assertNotNull(newNodeId); + assertNotNull(node.directParentNodeIds); + assertEquals(1, node.directParentNodeIds.size()); + assertTrue(node.directParentNodeIds.contains(tdp.node3.id)); + assertNotNull(node.parentNodeIds); + assertEquals(2, node.parentNodeIds.size()); + assertTrue(node.parentNodeIds.contains(tdp.node3.id)); + assertTrue(node.parentNodeIds.contains(tdp.node1.id)); + assertNotNull(node.directChildNodeIds); + assertTrue(node.directChildNodeIds.isEmpty()); + assertNotNull(node.childNodeIds); + assertTrue(node.childNodeIds.isEmpty()); + + // now check that the child links were updated correctly for the parent + node = hierarchyService.getNodeById(tdp.node3.id); + assertNotNull(node); + assertEquals(tdp.node3.id, node.id); + assertNotNull(node.directChildNodeIds); + assertEquals(2, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(newNodeId)); + assertTrue(node.directChildNodeIds.contains(tdp.node5.id)); + assertNotNull(node.childNodeIds); + assertEquals(2, node.childNodeIds.size()); + assertTrue(node.childNodeIds.contains(newNodeId)); + assertTrue(node.childNodeIds.contains(tdp.node5.id)); + + // check that adding a node without a parent puts the node at the top of the hierarchy + // NOTE: not currently supported, so this should die + try { + node = hierarchyService.addNode(TestDataPreload.HIERARCHYA, null); + fail("Should have thrown exception"); + } catch (RuntimeException e) { + assertNotNull(e); + } + + // check that attempting to add a node to a non-existent node fails + try { + node = hierarchyService.addNode(TestDataPreload.HIERARCHYA, TestDataPreload.INVALID_NODE_ID); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e); + } + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#removeNode(java.lang.String)}. + */ + public void testRemoveNode() { + HierarchyNode node = null; + + // remove a node with no children + node = hierarchyService.removeNode(tdp.node8.id); + assertNotNull(node); + assertNotNull(node.directChildNodeIds); + assertEquals(2, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(tdp.node6.id)); + assertTrue(node.directChildNodeIds.contains(tdp.node7.id)); + + // also check the root was updated correctly + node = hierarchyService.getNodeById(tdp.node1.id); + assertNotNull(node); + assertEquals(tdp.node1.id, node.id); + assertNotNull(node.directChildNodeIds); + assertEquals(3, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(tdp.node2.id)); + assertTrue(node.directChildNodeIds.contains(tdp.node3.id)); + assertTrue(node.directChildNodeIds.contains(tdp.node4.id)); + assertNotNull(node.childNodeIds); + assertEquals(6, node.childNodeIds.size()); + assertTrue(node.childNodeIds.contains(tdp.node2.id)); + assertTrue(node.childNodeIds.contains(tdp.node3.id)); + assertTrue(node.childNodeIds.contains(tdp.node4.id)); + assertTrue(node.childNodeIds.contains(tdp.node5.id)); + assertTrue(node.childNodeIds.contains(tdp.node6.id)); + assertTrue(node.childNodeIds.contains(tdp.node7.id)); + + // remove another node + node = hierarchyService.removeNode(tdp.node2.id); + assertNotNull(node); + assertNotNull(node.directChildNodeIds); + assertEquals(2, node.directChildNodeIds.size()); + assertTrue(node.childNodeIds.contains(tdp.node3.id)); + assertTrue(node.childNodeIds.contains(tdp.node4.id)); + + // also check the root was updated correctly + node = hierarchyService.getNodeById(tdp.node1.id); + assertNotNull(node); + assertEquals(tdp.node1.id, node.id); + assertNotNull(node.directChildNodeIds); + assertEquals(2, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(tdp.node3.id)); + assertTrue(node.directChildNodeIds.contains(tdp.node4.id)); + assertNotNull(node.childNodeIds); + assertEquals(5, node.childNodeIds.size()); + assertTrue(node.childNodeIds.contains(tdp.node3.id)); + assertTrue(node.childNodeIds.contains(tdp.node4.id)); + assertTrue(node.childNodeIds.contains(tdp.node5.id)); + assertTrue(node.childNodeIds.contains(tdp.node6.id)); + assertTrue(node.childNodeIds.contains(tdp.node7.id)); + + // cannot remove root node + try { + node = hierarchyService.removeNode(tdp.node1.id); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot remove nodes with children + try { + node = hierarchyService.removeNode(tdp.node4.id); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + try { + node = hierarchyService.removeNode(tdp.node3.id); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot remove nodes with multiple parents + try { + node = hierarchyService.removeNode(tdp.node10.id); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot use invalid node id (exception) + try { + node = hierarchyService.removeNode(TestDataPreload.INVALID_NODE_ID); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot use null node id (exception) + try { + node = hierarchyService.removeNode(null); + fail("Should have thrown exception"); + } catch (NullPointerException e) { + assertNotNull(e.getMessage()); + } + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#saveNodeMetaData(java.lang.String, java.lang.String, java.lang.String)}. + */ + public void testSaveNodeMetaData() { + HierarchyNode node = null; + + // saving node data + node = hierarchyService.saveNodeMetaData(tdp.node2.id, "Node TWO", "this is a description!", "TOKEN2"); + assertNotNull(node); + assertEquals(node.id, tdp.node2.id); + assertEquals("Node TWO", node.title); + assertEquals("this is a description!", node.description); + assertEquals("TOKEN2", node.permToken); + + // saving some nulls (should be ok) + node = hierarchyService.saveNodeMetaData(tdp.node2.id, null, "DESC", ""); + assertNotNull(node); + assertEquals(node.id, tdp.node2.id); + assertEquals("Node TWO", node.title); + assertEquals("DESC", node.description); + assertNull(node.permToken); + + // saving all nulls (should be save as previous values) + node = hierarchyService.saveNodeMetaData(tdp.node2.id, null, null, null); + assertNotNull(node); + assertEquals(node.id, tdp.node2.id); + assertEquals("Node TWO", node.title); + assertEquals("DESC", node.description); + assertNull(node.permToken); + + // saving empty strings (should blank everything out) + node = hierarchyService.saveNodeMetaData(tdp.node2.id, "", "", ""); + assertNotNull(node); + assertEquals(node.id, tdp.node2.id); + assertNull(node.title); + assertNull(node.description); + assertNull(node.permToken); + + // cannot use invalid node id (exception) + try { + node = hierarchyService.saveNodeMetaData(TestDataPreload.INVALID_NODE_ID, null, null, null); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot use null node id (exception) + try { + node = hierarchyService.saveNodeMetaData(null, null, null, null); + fail("Should have thrown exception"); + } catch (NullPointerException e) { + assertNotNull(e.getMessage()); + } + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#setNodeDisabled(java.lang.String, java.lang.Boolean)}. + */ + public void testSetNodeDisabled() { + + HierarchyNode node = null; + + // basic node creation, default is enabled (i.e. isDisabled is false) + node = hierarchyService.saveNodeMetaData(tdp.node2.id, "Node TWO", "this is a description!", "TOKEN2"); + assertNotNull(node); + assertEquals(node.id, tdp.node2.id); + assertEquals(node.isDisabled, Boolean.FALSE); + + // disabling a node + node = hierarchyService.setNodeDisabled(tdp.node2.id, Boolean.TRUE); + assertNotNull(node); + assertEquals(node.id, tdp.node2.id); + assertEquals(node.isDisabled, Boolean.TRUE); + + // disabling an already-disabled node + node = hierarchyService.setNodeDisabled(tdp.node2.id, Boolean.TRUE); + assertNotNull(node); + assertEquals(node.id, tdp.node2.id); + assertEquals(node.isDisabled, Boolean.TRUE); + + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#addChildRelation(java.lang.String, java.lang.String)}. + */ + public void testAddChildRelation() { + HierarchyNode node = null; + + // add new children + node = hierarchyService.addChildRelation(tdp.node2.id, tdp.node6.id); + assertNotNull(node); + assertNotNull(node.directChildNodeIds); + assertEquals(1, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(tdp.node6.id)); + assertNotNull(node.childNodeIds); + assertEquals(1, node.childNodeIds.size()); + assertTrue(node.childNodeIds.contains(tdp.node6.id)); + + node = hierarchyService.addChildRelation(tdp.node3.id, tdp.node7.id); + assertNotNull(node); + assertNotNull(node.directChildNodeIds); + assertEquals(2, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(tdp.node5.id)); + assertTrue(node.directChildNodeIds.contains(tdp.node7.id)); + + // add children which are already there + node = hierarchyService.addChildRelation(tdp.node3.id, tdp.node5.id); + assertNotNull(node); + assertNotNull(node.directChildNodeIds); + assertEquals(2, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(tdp.node5.id)); + assertTrue(node.directChildNodeIds.contains(tdp.node7.id)); + + node = hierarchyService.addChildRelation(tdp.node4.id, tdp.node7.id); + assertNotNull(node); + assertNotNull(node.directChildNodeIds); + assertEquals(3, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(tdp.node6.id)); + + // cannot add this node as a child of itself + try { + node = hierarchyService.addChildRelation(tdp.node7.id, tdp.node7.id); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot create a cycle by adding a child which is already a child or parent of this node + // (should probably check distance from the root...) + try { + node = hierarchyService.addChildRelation(tdp.node7.id, tdp.node4.id); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + try { + node = hierarchyService.addChildRelation(tdp.node7.id, tdp.node1.id); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + try { + node = hierarchyService.addChildRelation(tdp.node5.id, tdp.node3.id); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot use invalid node ids (exception) + try { + node = hierarchyService.addChildRelation(TestDataPreload.INVALID_NODE_ID, tdp.node6.id); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + try { + node = hierarchyService.addChildRelation(tdp.node2.id, TestDataPreload.INVALID_NODE_ID); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot use null node id (exception) + try { + node = hierarchyService.addChildRelation(null, tdp.node6.id); + fail("Should have thrown exception"); + } catch (NullPointerException e) { + assertNotNull(e.getMessage()); + } + + try { + node = hierarchyService.addChildRelation(tdp.node2.id, null); + fail("Should have thrown exception"); + } catch (NullPointerException e) { + assertNotNull(e.getMessage()); + } + + //fail("Not yet implemented"); + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#removeChildRelation(java.lang.String, java.lang.String)}. + */ + public void testRemoveChildRelation() { + HierarchyNode node = null; + + // create extra relation first + node = hierarchyService.addChildRelation(tdp.node2.id, tdp.node6.id); + + // remove a child + node = hierarchyService.removeChildRelation(tdp.node11.id, tdp.node10.id); + assertNotNull(node); + assertNotNull(node.directChildNodeIds); + assertEquals(0, node.directChildNodeIds.size()); + assertNotNull(node.childNodeIds); + assertEquals(0, node.childNodeIds.size()); + + node = hierarchyService.removeChildRelation(tdp.node4.id, tdp.node6.id); + assertNotNull(node); + assertNotNull(node.directChildNodeIds); + assertEquals(2, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(tdp.node7.id)); + assertTrue(node.directChildNodeIds.contains(tdp.node8.id)); + assertNotNull(node.childNodeIds); + assertEquals(2, node.childNodeIds.size()); + assertTrue(node.childNodeIds.contains(tdp.node7.id)); + assertTrue(node.childNodeIds.contains(tdp.node8.id)); + + // remove child which is not a child (this is ok) + node = hierarchyService.removeChildRelation(tdp.node3.id, tdp.node6.id); + + node = hierarchyService.removeChildRelation(tdp.node3.id, tdp.node2.id); + + // cannot remove myself as a child of myself + try { + node = hierarchyService.removeChildRelation(tdp.node2.id, tdp.node2.id); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot orphan nodes by removing a child relation (must use remove node) + try { + node = hierarchyService.removeChildRelation(tdp.node1.id, tdp.node3.id); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + try { + node = hierarchyService.removeChildRelation(tdp.node3.id, tdp.node5.id); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot use invalid node ids (exception) + try { + node = hierarchyService.removeChildRelation(TestDataPreload.INVALID_NODE_ID, tdp.node6.id); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + try { + node = hierarchyService.removeChildRelation(tdp.node2.id, TestDataPreload.INVALID_NODE_ID); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot use null node id (exception) + try { + node = hierarchyService.removeChildRelation(null, tdp.node6.id); + fail("Should have thrown exception"); + } catch (NullPointerException e) { + assertNotNull(e.getMessage()); + } + + try { + node = hierarchyService.removeChildRelation(tdp.node2.id, null); + fail("Should have thrown exception"); + } catch (NullPointerException e) { + assertNotNull(e.getMessage()); + } + + // fail("Not yet implemented"); + } + + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#addParentRelation(java.lang.String, java.lang.String)}. + *//** + public void testAddParentRelation() { + // add new parents + + // add parents which are already there + + // cannot remove all parents (must leave at least one) + + // cannot add parents to the root node + + // cannot create a cycle by adding a parent which is already a child or parent of this node + + // cannot add parents nodes which do not exist (should fail) + + // cannot use invalid node id (exception) + + // cannot use invalid parent node id (exception) + + // cannot use null node id (exception) + + fail("Not yet implemented"); + }**/ + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#removeParentRelation(java.lang.String, java.lang.String)}. + *//** + public void testRemoveParentRelation() { + // cannot remove all parents (must leave at least one) + + fail("Not yet implemented"); + }**/ + + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#getNodesWithToken(java.lang.String)}. + */ + public void testGetNodesWithToken() { + Set nodeIds; + + // get all the nodes with a specific token + nodeIds = hierarchyService.getNodesWithToken(TestDataPreload.HIERARCHYA, TestDataPreload.PERM_TOKEN_1); + assertNotNull(nodeIds); + assertEquals(3, nodeIds.size()); + assertTrue(nodeIds.contains(tdp.node2.id)); + assertTrue(nodeIds.contains(tdp.node3.id)); + assertTrue(nodeIds.contains(tdp.node5.id)); + + nodeIds = hierarchyService.getNodesWithToken(TestDataPreload.HIERARCHYB, TestDataPreload.PERM_TOKEN_1); + assertNotNull(nodeIds); + assertEquals(1, nodeIds.size()); + assertTrue(nodeIds.contains(tdp.node10.id)); + + nodeIds = hierarchyService.getNodesWithToken(TestDataPreload.HIERARCHYA, TestDataPreload.PERM_TOKEN_2); + assertNotNull(nodeIds); + assertEquals(1, nodeIds.size()); + assertTrue(nodeIds.contains(tdp.node4.id)); + + // attempt to get nodes for invalid token + nodeIds = hierarchyService.getNodesWithToken(TestDataPreload.HIERARCHYA, TestDataPreload.INVALID_PERM_TOKEN); + assertNotNull(nodeIds); + assertEquals(0, nodeIds.size()); + + // cannot use invalid hierarchy + try { + hierarchyService.getNodesWithToken(TestDataPreload.INVALID_HIERARCHY, TestDataPreload.PERM_TOKEN_1); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot get null token + try { + hierarchyService.getNodesWithToken(TestDataPreload.HIERARCHYA, null); + fail("Should have thrown exception"); + } catch (NullPointerException e) { + assertNotNull(e.getMessage()); + } + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#getNodesWithTokens(java.lang.String[])}. + */ + public void testGetNodesWithTokens() { + Set nodeIds; + Map> tokenNodes; + + // get nodes for tokens + tokenNodes = hierarchyService.getNodesWithTokens(TestDataPreload.HIERARCHYA, + new String[] {TestDataPreload.PERM_TOKEN_1, TestDataPreload.PERM_TOKEN_2}); + assertNotNull(tokenNodes); + assertEquals(2, tokenNodes.size()); + nodeIds = tokenNodes.get(TestDataPreload.PERM_TOKEN_1); + assertEquals(3, nodeIds.size()); + assertTrue(nodeIds.contains(tdp.node2.id)); + assertTrue(nodeIds.contains(tdp.node3.id)); + assertTrue(nodeIds.contains(tdp.node5.id)); + nodeIds = tokenNodes.get(TestDataPreload.PERM_TOKEN_2); + assertEquals(1, nodeIds.size()); + assertTrue(nodeIds.contains(tdp.node4.id)); + + // mix valid and invalid tokens + tokenNodes = hierarchyService.getNodesWithTokens(TestDataPreload.HIERARCHYB, + new String[] {TestDataPreload.PERM_TOKEN_1, TestDataPreload.PERM_TOKEN_2}); + assertNotNull(tokenNodes); + assertEquals(2, tokenNodes.size()); + nodeIds = tokenNodes.get(TestDataPreload.PERM_TOKEN_1); + assertEquals(1, nodeIds.size()); + assertTrue(nodeIds.contains(tdp.node10.id)); + nodeIds = tokenNodes.get(TestDataPreload.PERM_TOKEN_2); + assertEquals(0, nodeIds.size()); + + // attempt to get nodes for invalid token + tokenNodes = hierarchyService.getNodesWithTokens(TestDataPreload.HIERARCHYA, + new String[] {TestDataPreload.INVALID_PERM_TOKEN}); + assertNotNull(tokenNodes); + assertEquals(1, tokenNodes.size()); + nodeIds = tokenNodes.get(TestDataPreload.INVALID_PERM_TOKEN); + assertEquals(0, nodeIds.size()); + + // cannot use invalid hierarchy + try { + hierarchyService.getNodesWithTokens(TestDataPreload.INVALID_HIERARCHY, + new String[] {TestDataPreload.PERM_TOKEN_1}); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot get null token + try { + hierarchyService.getNodesWithTokens(TestDataPreload.HIERARCHYA, null); + fail("Should have thrown exception"); + } catch (NullPointerException e) { + assertNotNull(e.getMessage()); + } + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#checkUserNodePerm(java.lang.String, java.lang.String, java.lang.String)}. + */ + public void testCheckUserNodePerm() { + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node1.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node2.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node3.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node4.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node5.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node6.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node7.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node8.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node1.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node2.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node3.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node4.id, TestDataPreload.PERM_ONE) ); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node5.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node6.id, TestDataPreload.PERM_ONE) ); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node7.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node8.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node1.id, TestDataPreload.PERM_ONE) ); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node2.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node3.id, TestDataPreload.PERM_ONE) ); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node4.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node5.id, TestDataPreload.PERM_ONE) ); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node6.id, TestDataPreload.PERM_ONE) ); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node7.id, TestDataPreload.PERM_ONE) ); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node8.id, TestDataPreload.PERM_ONE) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node1.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node2.id, TestDataPreload.PERM_TWO) ); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node3.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node4.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node5.id, TestDataPreload.PERM_TWO) ); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node6.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node7.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node8.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node1.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node2.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node3.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node4.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node5.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node6.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node7.id, TestDataPreload.PERM_TWO) ); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.ACCESS_USER_ID, tdp.node8.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node1.id, TestDataPreload.PERM_TWO) ); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node2.id, TestDataPreload.PERM_TWO) ); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node3.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node4.id, TestDataPreload.PERM_TWO) ); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node5.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node6.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node7.id, TestDataPreload.PERM_TWO) ); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node8.id, TestDataPreload.PERM_TWO) ); + + try { + hierarchyService.checkUserNodePerm(null, "BBBBBB", "CCCCCCCCCCCCCCC"); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + try { + hierarchyService.checkUserNodePerm("AAAAAAAAAA", null, "CCCCCCCCCCCCCCC"); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + try { + hierarchyService.checkUserNodePerm("AAAAAAAAAA", "BBBBBB", null); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#getNodesForUserPerm(java.lang.String, java.lang.String)}. + */ + public void testGetNodesForUserPerm() { + Set nodes = null; + + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.USER_ID, TestDataPreload.PERM_ONE); + assertNotNull(nodes); + assertEquals(0, nodes.size()); + + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.USER_ID, TestDataPreload.PERM_TWO); + assertNotNull(nodes); + assertEquals(2, nodes.size()); + assertTrue( nodes.contains(tdp.node3) ); + assertTrue( nodes.contains(tdp.node6) ); + + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.ACCESS_USER_ID, TestDataPreload.PERM_ONE); + assertNotNull(nodes); + assertEquals(2, nodes.size()); + assertTrue( nodes.contains(tdp.node5) ); + assertTrue( nodes.contains(tdp.node7) ); + + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.ACCESS_USER_ID, TestDataPreload.PERM_TWO); + assertNotNull(nodes); + assertEquals(1, nodes.size()); + assertTrue( nodes.contains(tdp.node8) ); + + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.MAINT_USER_ID, TestDataPreload.PERM_ONE); + assertNotNull(nodes); + assertEquals(5, nodes.size()); + assertTrue( nodes.contains(tdp.node2) ); + assertTrue( nodes.contains(tdp.node4) ); + assertTrue( nodes.contains(tdp.node6) ); + assertTrue( nodes.contains(tdp.node7) ); + assertTrue( nodes.contains(tdp.node8) ); + + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.MAINT_USER_ID, TestDataPreload.PERM_TWO); + assertNotNull(nodes); + assertEquals(3, nodes.size()); + assertTrue( nodes.contains(tdp.node2) ); + assertTrue( nodes.contains(tdp.node3) ); + assertTrue( nodes.contains(tdp.node5) ); + + // invalids + + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.USER_ID, "XXXXXXXXX"); + assertNotNull(nodes); + assertEquals(0, nodes.size()); + + nodes = hierarchyService.getNodesForUserPerm("XXXXXXX", TestDataPreload.PERM_ONE); + assertNotNull(nodes); + assertEquals(0, nodes.size()); + + try { + hierarchyService.getNodesForUserPerm(null, "XXXXXXXXX"); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + try { + hierarchyService.getNodesForUserPerm("XXXXXXXX", null); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#getUserIdsForNodesPerm(java.lang.String[], java.lang.String)}. + */ + public void testGetUserIdsForNodesPerm() { + Set userIds = null; + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node1.id}, TestDataPreload.PERM_ONE); + assertNotNull(userIds); + assertEquals(0, userIds.size()); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node2.id}, TestDataPreload.PERM_ONE); + assertNotNull(userIds); + assertEquals(1, userIds.size()); + assertTrue(userIds.contains(TestDataPreload.MAINT_USER_ID)); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node3.id}, TestDataPreload.PERM_ONE); + assertNotNull(userIds); + assertEquals(0, userIds.size()); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node4.id}, TestDataPreload.PERM_ONE); + assertNotNull(userIds); + assertEquals(1, userIds.size()); + assertTrue(userIds.contains(TestDataPreload.MAINT_USER_ID)); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node5.id}, TestDataPreload.PERM_ONE); + assertNotNull(userIds); + assertEquals(1, userIds.size()); + assertTrue(userIds.contains(TestDataPreload.ACCESS_USER_ID)); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node6.id}, TestDataPreload.PERM_ONE); + assertNotNull(userIds); + assertEquals(1, userIds.size()); + assertTrue(userIds.contains(TestDataPreload.MAINT_USER_ID)); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node7.id}, TestDataPreload.PERM_ONE); + assertNotNull(userIds); + assertEquals(2, userIds.size()); + assertTrue(userIds.contains(TestDataPreload.MAINT_USER_ID)); + assertTrue(userIds.contains(TestDataPreload.ACCESS_USER_ID)); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node8.id}, TestDataPreload.PERM_ONE); + assertNotNull(userIds); + assertEquals(1, userIds.size()); + assertTrue(userIds.contains(TestDataPreload.MAINT_USER_ID)); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node1.id}, TestDataPreload.PERM_TWO); + assertNotNull(userIds); + assertEquals(0, userIds.size()); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node2.id}, TestDataPreload.PERM_TWO); + assertNotNull(userIds); + assertEquals(1, userIds.size()); + assertTrue(userIds.contains(TestDataPreload.MAINT_USER_ID)); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node3.id}, TestDataPreload.PERM_TWO); + assertNotNull(userIds); + assertEquals(2, userIds.size()); + assertTrue(userIds.contains(TestDataPreload.MAINT_USER_ID)); + assertTrue(userIds.contains(TestDataPreload.USER_ID)); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node4.id}, TestDataPreload.PERM_TWO); + assertNotNull(userIds); + assertEquals(0, userIds.size()); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node5.id}, TestDataPreload.PERM_TWO); + assertNotNull(userIds); + assertEquals(1, userIds.size()); + assertTrue(userIds.contains(TestDataPreload.MAINT_USER_ID)); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node6.id}, TestDataPreload.PERM_TWO); + assertNotNull(userIds); + assertEquals(1, userIds.size()); + assertTrue(userIds.contains(TestDataPreload.USER_ID)); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node7.id}, TestDataPreload.PERM_TWO); + assertNotNull(userIds); + assertEquals(0, userIds.size()); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node8.id}, TestDataPreload.PERM_TWO); + assertNotNull(userIds); + assertEquals(1, userIds.size()); + assertTrue(userIds.contains(TestDataPreload.ACCESS_USER_ID)); + + // multiple + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node2.id, tdp.node3.id, tdp.node4.id, tdp.node5.id}, TestDataPreload.PERM_ONE); + assertNotNull(userIds); + assertEquals(2, userIds.size()); + assertTrue(userIds.contains(TestDataPreload.ACCESS_USER_ID)); + assertTrue(userIds.contains(TestDataPreload.MAINT_USER_ID)); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {tdp.node2.id, tdp.node3.id, tdp.node4.id, tdp.node5.id}, TestDataPreload.PERM_TWO); + assertNotNull(userIds); + assertEquals(2, userIds.size()); + assertTrue(userIds.contains(TestDataPreload.USER_ID)); + assertTrue(userIds.contains(TestDataPreload.MAINT_USER_ID)); + + // invalids + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {}, TestDataPreload.PERM_ONE); + assertNotNull(userIds); + assertEquals(0, userIds.size()); + + userIds = hierarchyService.getUserIdsForNodesPerm(new String[] {}, TestDataPreload.PERM_TWO); + assertNotNull(userIds); + assertEquals(0, userIds.size()); + + try { + hierarchyService.getUserIdsForNodesPerm(null, "XXXXXXXXX"); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + try { + hierarchyService.getUserIdsForNodesPerm(new String[] {"XXXXXXXX"}, null); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#getPermsForUserNodes(java.lang.String, java.lang.String[])}. + */ + public void testGetPermsForUserNodes() { + Set perms = null; + + perms = hierarchyService.getPermsForUserNodes(TestDataPreload.MAINT_USER_ID, new String[] {tdp.node1.id}); + assertNotNull(perms); + assertEquals(0, perms.size()); + + perms = hierarchyService.getPermsForUserNodes(TestDataPreload.MAINT_USER_ID, new String[] {tdp.node2.id}); + assertNotNull(perms); + assertEquals(2, perms.size()); + assertTrue(perms.contains(TestDataPreload.PERM_ONE)); + assertTrue(perms.contains(TestDataPreload.PERM_TWO)); + + perms = hierarchyService.getPermsForUserNodes(TestDataPreload.MAINT_USER_ID, new String[] {tdp.node3.id}); + assertNotNull(perms); + assertEquals(1, perms.size()); + assertTrue(perms.contains(TestDataPreload.PERM_TWO)); + + perms = hierarchyService.getPermsForUserNodes(TestDataPreload.MAINT_USER_ID, new String[] {tdp.node4.id}); + assertNotNull(perms); + assertEquals(1, perms.size()); + assertTrue(perms.contains(TestDataPreload.PERM_ONE)); + + perms = hierarchyService.getPermsForUserNodes(TestDataPreload.MAINT_USER_ID, new String[] {tdp.node5.id}); + assertNotNull(perms); + assertEquals(1, perms.size()); + assertTrue(perms.contains(TestDataPreload.PERM_TWO)); + + perms = hierarchyService.getPermsForUserNodes(TestDataPreload.MAINT_USER_ID, new String[] {tdp.node6.id}); + assertNotNull(perms); + assertEquals(1, perms.size()); + assertTrue(perms.contains(TestDataPreload.PERM_ONE)); + + perms = hierarchyService.getPermsForUserNodes(TestDataPreload.MAINT_USER_ID, new String[] {tdp.node7.id}); + assertNotNull(perms); + assertEquals(1, perms.size()); + assertTrue(perms.contains(TestDataPreload.PERM_ONE)); + + perms = hierarchyService.getPermsForUserNodes(TestDataPreload.MAINT_USER_ID, new String[] {tdp.node8.id}); + assertNotNull(perms); + assertEquals(1, perms.size()); + assertTrue(perms.contains(TestDataPreload.PERM_ONE)); + + // multiple + perms = hierarchyService.getPermsForUserNodes(TestDataPreload.MAINT_USER_ID, new String[] {tdp.node3.id, tdp.node4.id, tdp.node5.id, tdp.node6.id}); + assertNotNull(perms); + assertEquals(2, perms.size()); + assertTrue(perms.contains(TestDataPreload.PERM_ONE)); + assertTrue(perms.contains(TestDataPreload.PERM_TWO)); + + // invalids + perms = hierarchyService.getPermsForUserNodes(TestDataPreload.ACCESS_USER_ID, new String[] {}); + assertNotNull(perms); + assertEquals(0, perms.size()); + + perms = hierarchyService.getPermsForUserNodes(TestDataPreload.MAINT_USER_ID, new String[] {}); + assertNotNull(perms); + assertEquals(0, perms.size()); + + perms = hierarchyService.getPermsForUserNodes(TestDataPreload.USER_ID, new String[] {}); + assertNotNull(perms); + assertEquals(0, perms.size()); + + try { + hierarchyService.getPermsForUserNodes(null, new String[] {"XXXXXXXX"}); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + try { + hierarchyService.getPermsForUserNodes("XXXXXXXXXXX", null); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + } + + public void testGetUsersAndPermsForNodes() { + Map>> map = null; + + map = hierarchyService.getUsersAndPermsForNodes(tdp.node3.id); + assertNotNull(map); + assertEquals(1, map.size()); + Map> userPerms = map.get(tdp.node3.id); + assertEquals(2, userPerms.size()); + assertEquals(userPerms.get(TestDataPreload.USER_ID).size(), 1); + assertEquals(userPerms.get(TestDataPreload.MAINT_USER_ID).size(), 1); + + try { + hierarchyService.getUsersAndPermsForNodes((String[])null); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + try { + hierarchyService.getUsersAndPermsForNodes(); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + } + + public void testGetNodesAndPermsForUser() { + Map>> map = null; + + map = hierarchyService.getNodesAndPermsForUser(TestDataPreload.ACCESS_USER_ID); + assertNotNull(map); + assertEquals(1, map.size()); + assertEquals(3, map.get(TestDataPreload.ACCESS_USER_ID).size()); + + try { + hierarchyService.getNodesAndPermsForUser((String[])null); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + try { + hierarchyService.getNodesAndPermsForUser(); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#assignUserNodePerm(java.lang.String, java.lang.String, java.lang.String, boolean)}. + */ + public void testAssignUserNodePerm() { + Set nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.MAINT_USER_ID, TestDataPreload.PERM_ONE); + assertEquals(5, nodes.size()); + + // add existing one - should be no change + hierarchyService.assignUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node2.id, TestDataPreload.PERM_ONE, false); + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.MAINT_USER_ID, TestDataPreload.PERM_ONE); + assertEquals(5, nodes.size()); + + // add existing one - should be no change + hierarchyService.assignUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node4.id, TestDataPreload.PERM_ONE, true); + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.MAINT_USER_ID, TestDataPreload.PERM_ONE); + assertEquals(5, nodes.size()); + + // now add some that do not exist already + hierarchyService.assignUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node3.id, TestDataPreload.PERM_ONE, false); + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.MAINT_USER_ID, TestDataPreload.PERM_ONE); + assertEquals(6, nodes.size()); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node3.id, TestDataPreload.PERM_ONE) ); + + hierarchyService.assignUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node3.id, TestDataPreload.PERM_ONE, true); + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.MAINT_USER_ID, TestDataPreload.PERM_ONE); + assertEquals(7, nodes.size()); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node5.id, TestDataPreload.PERM_ONE) ); + + // now test adding a completely different permission + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.USER_ID, TestDataPreload.PERM_THREE); + assertEquals(0, nodes.size()); + + hierarchyService.assignUserNodePerm(TestDataPreload.USER_ID, tdp.node1.id, TestDataPreload.PERM_THREE, false); + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.USER_ID, TestDataPreload.PERM_THREE); + assertEquals(1, nodes.size()); + assertTrue( hierarchyService.checkUserNodePerm(TestDataPreload.USER_ID, tdp.node1.id, TestDataPreload.PERM_THREE) ); + + hierarchyService.assignUserNodePerm(TestDataPreload.USER_ID, tdp.node1.id, TestDataPreload.PERM_THREE, true); + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.USER_ID, TestDataPreload.PERM_THREE); + assertEquals(8, nodes.size()); + + + try { + hierarchyService.assignUserNodePerm(null, tdp.node3.id, TestDataPreload.PERM_ONE, false); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + try { + hierarchyService.assignUserNodePerm(TestDataPreload.MAINT_USER_ID, null, TestDataPreload.PERM_ONE, false); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + try { + hierarchyService.assignUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node3.id, null, false); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + } + + /** + * Test method for {@link org.sakaiproject.hierarchy.impl.HierarchyServiceImpl#removeUserNodePerm(java.lang.String, java.lang.String, java.lang.String, boolean)}. + */ + public void testRemoveUserNodePerm() { + Set nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.MAINT_USER_ID, TestDataPreload.PERM_ONE); + assertEquals(5, nodes.size()); + + hierarchyService.removeUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node2.id, TestDataPreload.PERM_ONE, false); + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.MAINT_USER_ID, TestDataPreload.PERM_ONE); + assertEquals(4, nodes.size()); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node2.id, TestDataPreload.PERM_ONE) ); + + hierarchyService.removeUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node4.id, TestDataPreload.PERM_ONE, true); + nodes = hierarchyService.getNodesForUserPerm(TestDataPreload.MAINT_USER_ID, TestDataPreload.PERM_ONE); + assertEquals(0, nodes.size()); + assertFalse( hierarchyService.checkUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node4.id, TestDataPreload.PERM_ONE) ); + + // invalids don't cause failure + hierarchyService.removeUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node2.id, "XXXXX", false); + hierarchyService.removeUserNodePerm(TestDataPreload.MAINT_USER_ID, "XXXX", "XXXXX", false); + hierarchyService.removeUserNodePerm("XXX", "XXXX", "XXXXX", false); + + try { + hierarchyService.removeUserNodePerm(null, tdp.node3.id, TestDataPreload.PERM_ONE, false); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + try { + hierarchyService.removeUserNodePerm(TestDataPreload.MAINT_USER_ID, null, TestDataPreload.PERM_ONE, false); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + try { + hierarchyService.removeUserNodePerm(TestDataPreload.MAINT_USER_ID, tdp.node3.id, null, false); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + } + + + + /* + HierarchyNode node = null; + Set children = new HashSet();; + + // add new children + children.add(tdp.node6.id); + node = hierarchyService.updateChildren(tdp.node2.id, children); + assertNotNull(node); + assertNotNull(node.directChildNodeIds); + assertEquals(1, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(tdp.node6.id)); + + children.add(tdp.node7.id); + children.add(tdp.node8.id); + node = hierarchyService.updateChildren(tdp.node2.id, children); + assertNotNull(node); + assertNotNull(node.directChildNodeIds); + assertEquals(3, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(tdp.node6.id)); + assertTrue(node.directChildNodeIds.contains(tdp.node7.id)); + assertTrue(node.directChildNodeIds.contains(tdp.node8.id)); + + // remove some children + children.clear(); + children.add(tdp.node7.id); + children.add(tdp.node8.id); + node = hierarchyService.updateChildren(tdp.node4.id, children); + assertNotNull(node); + assertNotNull(node.directChildNodeIds); + assertEquals(2, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(tdp.node7.id)); + assertTrue(node.directChildNodeIds.contains(tdp.node8.id)); + + // remove all children + children.clear(); + node = hierarchyService.updateChildren(tdp.node4.id, children); + assertNotNull(node); + assertNotNull(node.directChildNodeIds); + assertEquals(0, node.directChildNodeIds.size()); + + // update children to the identical set + children.clear(); + children.add(tdp.node5.id); + node = hierarchyService.updateChildren(tdp.node3.id, children); + assertNotNull(node); + assertNotNull(node.directChildNodeIds); + assertEquals(1, node.directChildNodeIds.size()); + assertTrue(node.directChildNodeIds.contains(tdp.node5.id)); + + // cannot add children nodes which do not exist (even if some are valid) + children.add(TestDataPreload.INVALID_NODE_ID); + try { + node = hierarchyService.updateChildren(tdp.node3.id, children); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot add child node which is equal to this node + children.clear(); + children.add(tdp.node5.id); + children.add(tdp.node3.id); + try { + node = hierarchyService.updateChildren(tdp.node3.id, children); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + children.clear(); + children.add(tdp.node3.id); + try { + node = hierarchyService.updateChildren(tdp.node3.id, children); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot remove child node so that it becomes orphaned + children.clear(); + children.add(tdp.node2.id); + children.add(tdp.node4.id); + try { + node = hierarchyService.updateChildren(tdp.node1.id, children); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + children.clear(); + children.add(tdp.node3.id); + children.add(tdp.node4.id); + try { + node = hierarchyService.updateChildren(tdp.node1.id, children); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot use invalid node id (exception) + children.clear(); + children.add(tdp.node6.id); + try { + node = hierarchyService.updateChildren(TestDataPreload.INVALID_NODE_ID, children); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot use invalid child node id (exception) + children.clear(); + children.add(tdp.node6.id); + children.add(TestDataPreload.INVALID_NODE_ID); + try { + node = hierarchyService.updateChildren(tdp.node2.id, children); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } + + // cannot use null node id (exception) + children.clear(); + try { + node = hierarchyService.updateChildren(null, children); + fail("Should have thrown exception"); + } catch (NullPointerException e) { + assertNotNull(e.getMessage()); + } + + */ + +} diff --git a/hierarchy/impl/src/test/org/sakaiproject/hierarchy/impl/test/data/TestDataPreload.java b/hierarchy/impl/src/test/org/sakaiproject/hierarchy/impl/test/data/TestDataPreload.java new file mode 100644 index 000000000000..356e5bb6ed2d --- /dev/null +++ b/hierarchy/impl/src/test/org/sakaiproject/hierarchy/impl/test/data/TestDataPreload.java @@ -0,0 +1,233 @@ +/****************************************************************************** + * TestDataPreload.java - created by Sakai App Builder -AZ + * + * Copyright (c) 2006 Sakai Project/Sakai Foundation + * Licensed under the Educational Community License version 1.0 + * + * A copy of the Educational Community License has been included in this + * distribution and is available at: http://www.opensource.org/licenses/ecl1.php + * + *****************************************************************************/ + +package org.sakaiproject.hierarchy.impl.test.data; + +import java.util.Set; +import java.util.TreeSet; + +import org.sakaiproject.genericdao.api.GenericDao; +import org.sakaiproject.hierarchy.dao.model.HierarchyNodeMetaData; +import org.sakaiproject.hierarchy.dao.model.HierarchyNodePermission; +import org.sakaiproject.hierarchy.dao.model.HierarchyPersistentNode; +import org.sakaiproject.hierarchy.impl.utils.HierarchyImplUtils; +import org.sakaiproject.hierarchy.model.HierarchyNode; + +/** + * Contains test data for preloading and test constants + * @author Aaron Zeckoski (aaronz@vt.edu) + */ +public class TestDataPreload { + + public GenericDao dao; + public void setDao(GenericDao dao) { + this.dao = dao; + } + + public void init() { + preloadTestData(dao); + } + + /** + * current user, access level user in LOCATION1_ID + */ + public final static String USER_ID = "user-11111111"; + public final static String USER_DISPLAY = "Aaron Zeckoski"; + /** + * access level user in LOCATION1_ID + */ + public final static String ACCESS_USER_ID = "access-2222222"; + public final static String ACCESS_USER_DISPLAY = "Regular User"; + /** + * maintain level user in LOCATION1_ID + */ + public final static String MAINT_USER_ID = "maint-33333333"; + public final static String MAINT_USER_DISPLAY = "Maint User"; + /** + * super admin user + */ + public final static String ADMIN_USER_ID = "admin"; + public final static String ADMIN_USER_DISPLAY = "Administrator"; + /** + * Invalid user (also can be used to simulate the anonymous user) + */ + public final static String INVALID_USER_ID = "invalid-UUUUUU"; + + /** + * this permission does not translate + */ + public final static String PERM_TOKEN_1 = "tokenKey1"; + /** + * this permission should translate downward + */ + public final static String PERM_TOKEN_2 = "tokenKey2"; + public final static String INVALID_PERM_TOKEN = "invalid-permtoken"; + + /** + * current location + */ + public final static String LOCATION1_ID = "/site/ref-1111111"; + public final static String LOCATION1_TITLE = "Location 1 title"; + public final static String LOCATION2_ID = "/site/ref-22222222"; + public final static String LOCATION2_TITLE = "Location 2 title"; + public final static String INVALID_LOCATION_ID = "invalid-LLLLLLLL"; + + // testing constants + public final static String HIERARCHYA = "hierarchyA"; + public final static String HIERARCHYB = "hierarchyB"; + public final static String INVALID_HIERARCHY = "hierarchy-invalid"; + public final static String INVALID_NODE_ID = "invalid-nodeID"; + + public final static String PERM_ONE = "permission.one"; + public final static String PERM_TWO = "permission.two"; + public final static String PERM_THREE = "permission.three"; + + // testing data objects here + public HierarchyPersistentNode pNode1 = new HierarchyPersistentNode(null, null, toCode("2,3,4"), toCode("2,3,4,5,6,7,8") ); + public HierarchyPersistentNode pNode2 = new HierarchyPersistentNode(toCode("1"), toCode("1"), null, null ); + public HierarchyPersistentNode pNode3 = new HierarchyPersistentNode(toCode("1"), toCode("1"), toCode("5"), toCode("5") ); + public HierarchyPersistentNode pNode4 = new HierarchyPersistentNode(toCode("1"), toCode("1"), toCode("6,7,8"), toCode("6,7,8") ); + public HierarchyPersistentNode pNode5 = new HierarchyPersistentNode(toCode("3"), toCode("1,3"), null, null ); + public HierarchyPersistentNode pNode6 = new HierarchyPersistentNode(toCode("4"), toCode("1,4"), null, null ); + public HierarchyPersistentNode pNode7 = new HierarchyPersistentNode(toCode("4"), toCode("1,4"), null, null ); + public HierarchyPersistentNode pNode8 = new HierarchyPersistentNode(toCode("4"), toCode("1,4"), null, null ); + public HierarchyPersistentNode pNode9 = new HierarchyPersistentNode(null, null, toCode("10"), toCode("10") ); + public HierarchyPersistentNode pNode10 = new HierarchyPersistentNode(toCode("9,11"), toCode("9,11"), null, null ); + public HierarchyPersistentNode pNode11 = new HierarchyPersistentNode(null, null, toCode("10"), toCode("10") ); + + public HierarchyNodeMetaData meta1 = new HierarchyNodeMetaData(pNode1, HIERARCHYA, Boolean.TRUE, USER_ID, "Univ of AZ", null, null, Boolean.FALSE); + public HierarchyNodeMetaData meta2 = new HierarchyNodeMetaData(pNode2, HIERARCHYA, Boolean.FALSE, USER_ID, "College of Engineering", null, PERM_TOKEN_1, Boolean.FALSE); + public HierarchyNodeMetaData meta3 = new HierarchyNodeMetaData(pNode3, HIERARCHYA, Boolean.FALSE, USER_ID, "College of Arts", null, PERM_TOKEN_1, Boolean.FALSE); + public HierarchyNodeMetaData meta4 = new HierarchyNodeMetaData(pNode4, HIERARCHYA, Boolean.FALSE, USER_ID, "College of Science", null, PERM_TOKEN_2, Boolean.FALSE); + public HierarchyNodeMetaData meta5 = new HierarchyNodeMetaData(pNode5, HIERARCHYA, Boolean.FALSE, USER_ID, "Dept of Art", null, PERM_TOKEN_1, Boolean.FALSE); + public HierarchyNodeMetaData meta6 = new HierarchyNodeMetaData(pNode6, HIERARCHYA, Boolean.FALSE, USER_ID, "Dept of Math", null, null, Boolean.FALSE); + public HierarchyNodeMetaData meta7 = new HierarchyNodeMetaData(pNode7, HIERARCHYA, Boolean.FALSE, USER_ID, "Dept of Physics", null, null, Boolean.FALSE); + public HierarchyNodeMetaData meta8 = new HierarchyNodeMetaData(pNode8, HIERARCHYA, Boolean.FALSE, USER_ID, "Dept of Biology", null, null, Boolean.FALSE); + public HierarchyNodeMetaData meta9 = new HierarchyNodeMetaData(pNode9, HIERARCHYB, Boolean.TRUE, USER_ID, "Univ of BZ", null, null, Boolean.FALSE); + public HierarchyNodeMetaData meta10 = new HierarchyNodeMetaData(pNode10, HIERARCHYB, Boolean.FALSE, USER_ID, "College of BZ", null, PERM_TOKEN_1, Boolean.FALSE); + public HierarchyNodeMetaData meta11 = new HierarchyNodeMetaData(pNode11, HIERARCHYB, Boolean.FALSE, USER_ID, "Provost of BZ", null, null, Boolean.FALSE); + + public HierarchyNode node1; + public HierarchyNode node2; + public HierarchyNode node3; + public HierarchyNode node4; + public HierarchyNode node5; + public HierarchyNode node6; + public HierarchyNode node7; + public HierarchyNode node8; + public HierarchyNode node9; + public HierarchyNode node10; + public HierarchyNode node11; + + public HierarchyNodePermission nodePerm1 ; + public HierarchyNodePermission nodePerm2 ; + public HierarchyNodePermission nodePerm3 ; + public HierarchyNodePermission nodePerm4 ; + public HierarchyNodePermission nodePerm5 ; + public HierarchyNodePermission nodePerm6 ; + public HierarchyNodePermission nodePerm7 ; + public HierarchyNodePermission nodePerm8 ; + public HierarchyNodePermission nodePerm9 ; + public HierarchyNodePermission nodePerm10; + public HierarchyNodePermission nodePerm11; + public HierarchyNodePermission nodePerm12; + public HierarchyNodePermission nodePerm13; + + public boolean preloaded = false; + /** + * Preload a bunch of test data into the database + * @param dao a generic dao + */ + public void preloadTestData(GenericDao dao) { + dao.save(pNode1); + dao.save(pNode2); + dao.save(pNode3); + dao.save(pNode4); + dao.save(pNode5); + dao.save(pNode6); + dao.save(pNode7); + dao.save(pNode8); + dao.save(pNode9); + dao.save(pNode10); + dao.save(pNode11); + + dao.save(meta1); + dao.save(meta2); + dao.save(meta3); + dao.save(meta4); + dao.save(meta5); + dao.save(meta6); + dao.save(meta7); + dao.save(meta8); + dao.save(meta9); + dao.save(meta10); + dao.save(meta11); + + node1 = HierarchyImplUtils.makeNode(pNode1, meta1); + node2 = HierarchyImplUtils.makeNode(pNode2, meta2); + node3 = HierarchyImplUtils.makeNode(pNode3, meta3); + node4 = HierarchyImplUtils.makeNode(pNode4, meta4); + node5 = HierarchyImplUtils.makeNode(pNode5, meta5); + node6 = HierarchyImplUtils.makeNode(pNode6, meta6); + node7 = HierarchyImplUtils.makeNode(pNode7, meta7); + node8 = HierarchyImplUtils.makeNode(pNode8, meta8); + node9 = HierarchyImplUtils.makeNode(pNode9, meta9); + node10 = HierarchyImplUtils.makeNode(pNode10, meta10); + node11 = HierarchyImplUtils.makeNode(pNode11, meta11); + + nodePerm1 = new HierarchyNodePermission(MAINT_USER_ID, pNode2.getId().toString(), PERM_ONE); + nodePerm2 = new HierarchyNodePermission(USER_ID, pNode3.getId().toString(), PERM_TWO); + nodePerm3 = new HierarchyNodePermission(MAINT_USER_ID, pNode3.getId().toString(), PERM_TWO); + nodePerm4 = new HierarchyNodePermission(MAINT_USER_ID, pNode4.getId().toString(), PERM_ONE); + nodePerm5 = new HierarchyNodePermission(MAINT_USER_ID, pNode5.getId().toString(), PERM_TWO); + nodePerm6 = new HierarchyNodePermission(ACCESS_USER_ID, pNode5.getId().toString(), PERM_ONE); + nodePerm7 = new HierarchyNodePermission(MAINT_USER_ID, pNode6.getId().toString(), PERM_ONE); + nodePerm8 = new HierarchyNodePermission(USER_ID, pNode6.getId().toString(), PERM_TWO); + nodePerm9 = new HierarchyNodePermission(MAINT_USER_ID, pNode7.getId().toString(), PERM_ONE); + nodePerm10 = new HierarchyNodePermission(ACCESS_USER_ID, pNode7.getId().toString(), PERM_ONE); + nodePerm11 = new HierarchyNodePermission(MAINT_USER_ID, pNode8.getId().toString(), PERM_ONE); + nodePerm12 = new HierarchyNodePermission(ACCESS_USER_ID, pNode8.getId().toString(), PERM_TWO); + nodePerm13 = new HierarchyNodePermission(MAINT_USER_ID, pNode2.getId().toString(), PERM_TWO); + + dao.save(nodePerm1); + dao.save(nodePerm2); + dao.save(nodePerm3); + dao.save(nodePerm4); + dao.save(nodePerm5); + dao.save(nodePerm6); + dao.save(nodePerm7); + dao.save(nodePerm8); + dao.save(nodePerm9); + dao.save(nodePerm10); + dao.save(nodePerm11); + dao.save(nodePerm12); + dao.save(nodePerm13); + + preloaded = true; + } + + /** + * Encode the comma delimited list of nodes + * @param commaDelimitedNums + * @return an encoded string + */ + private String toCode(String commaDelimitedNums) { + Set s = new TreeSet(); + if (commaDelimitedNums != null && !commaDelimitedNums.equals("")) { + String[] split = commaDelimitedNums.split(","); + for (int i = 0; i < split.length; i++) { + s.add( split[i] ); + } + } + return HierarchyImplUtils.makeEncodedNodeIdString(s); + } + +} diff --git a/hierarchy/pack/pom.xml b/hierarchy/pack/pom.xml new file mode 100644 index 000000000000..7d06e3376912 --- /dev/null +++ b/hierarchy/pack/pom.xml @@ -0,0 +1,29 @@ + + 4.0.0 + + + hierarchy + org.sakaiproject + 10.0-SNAPSHOT + + + Sakai Hierarchy Components Pack + org.sakaiproject.hierarchy + hierarchy-pack + + sakai-component + + + components + + + + + org.sakaiproject.hierarchy + hierarchy-impl + runtime + + + + + \ No newline at end of file diff --git a/hierarchy/pack/project.xml b/hierarchy/pack/project.xml new file mode 100644 index 000000000000..8070fa7a1232 --- /dev/null +++ b/hierarchy/pack/project.xml @@ -0,0 +1,62 @@ + + + 3 + ../../master/project.xml + sakai-hierarchy-pack + sakaiproject + sakai-hierarchy-pack + ${sakai.version} + + Sakai Project + http://www.sakaiproject.org/ + + 2006 + + + + components + + + + + + + + sakaiproject + sakai + ${sakai.plugin.version} + plugin + + + + + sakaiproject + sakai-hierarchy-impl + ${sakai.version} + + true + + + + + + generic-dao + generic-dao + 0.9.7 + + true + + + + + + + + + + diff --git a/hierarchy/pack/src/webapp/WEB-INF/components.xml b/hierarchy/pack/src/webapp/WEB-INF/components.xml new file mode 100644 index 000000000000..b157761ab08c --- /dev/null +++ b/hierarchy/pack/src/webapp/WEB-INF/components.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hierarchy/pack/src/webapp/WEB-INF/sakai-hibernate.xml b/hierarchy/pack/src/webapp/WEB-INF/sakai-hibernate.xml new file mode 100644 index 000000000000..48ef307014fd --- /dev/null +++ b/hierarchy/pack/src/webapp/WEB-INF/sakai-hibernate.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/hierarchy/pack/src/webapp/WEB-INF/spring-hibernate.xml b/hierarchy/pack/src/webapp/WEB-INF/spring-hibernate.xml new file mode 100644 index 000000000000..6f8a7e132b9c --- /dev/null +++ b/hierarchy/pack/src/webapp/WEB-INF/spring-hibernate.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + org/sakaiproject/hierarchy/dao/hbm/HierarchyPersistentNode.hbm.xml + org/sakaiproject/hierarchy/dao/hbm/HierarchyNodeMetaData.hbm.xml + org/sakaiproject/hierarchy/dao/hbm/HierarchyNodePermission.hbm.xml + + + + + + + + + + org.sakaiproject.hierarchy.dao.model.HierarchyPersistentNode + org.sakaiproject.hierarchy.dao.model.HierarchyNodeMetaData + org.sakaiproject.hierarchy.dao.model.HierarchyNodePermission + + + + + + + + + + + PROPAGATION_REQUIRED,readOnly + PROPAGATION_REQUIRED,readOnly + PROPAGATION_REQUIRED,readOnly + PROPAGATION_REQUIRED + + + + + diff --git a/hierarchy/pom.xml b/hierarchy/pom.xml new file mode 100644 index 000000000000..d3eaa6f9d8b7 --- /dev/null +++ b/hierarchy/pom.xml @@ -0,0 +1,99 @@ + + 4.0.0 + + + org.sakaiproject + master + 10.0-SNAPSHOT + ../master/pom.xml + + + Sakai Hierarchy + org.sakaiproject + hierarchy + 10.0-SNAPSHOT + + pom + + + Apereo Foundation + http://apereo.org + + 2007 + + + Hierarchy is meant to provide a high performance basic hierarchy to associate data + with, no data is stored in the hierarchy itself, it is simply there to allow you + to maintain the hierarchical structure and to provide methods to manipulate it and + query it + + + + + full + + true + + + api + impl + pack + + + + api + + api + + + + ddl + + impl/src/ddl + + + + + + + aaronz + Aaron Zeckoski + azeckoski@unicon.net + + Project Manager + Architect + Developer + + 0 + + + + + + Anthony Whyte + arwhyte@umich.edu + + + + + scm:svn:https://source.sakaiproject.org/contrib/caret/hierarchy/trunk + scm:svn:https://source.sakaiproject.org/contrib/caret/hierarchy/trunk + https://source.sakaiproject.org/contrib/caret/hierarchy/?root=contrib + + + + + + org.sakaiproject.hierarchy + hierarchy-api + ${project.version} + provided + + + org.sakaiproject.hierarchy + hierarchy-impl + ${project.version} + + + + diff --git a/hierarchy/project.properties b/hierarchy/project.properties new file mode 100644 index 000000000000..32507ebfc859 --- /dev/null +++ b/hierarchy/project.properties @@ -0,0 +1 @@ +maven.junit.usefile=false \ No newline at end of file diff --git a/hierarchy/project.xml b/hierarchy/project.xml new file mode 100644 index 000000000000..10c7a113b160 --- /dev/null +++ b/hierarchy/project.xml @@ -0,0 +1,30 @@ + + + 3 + ../master/project.xml + Sakai Hierarchy + sakaiproject + sakai-hierarchy + ${sakai.version} + + CARET, Cambridge University + http://caret.cam.ac.uk/ + + 2007 + + + + + + + sakaiproject + sakai + ${sakai.plugin.version} + plugin + + + + + +