001/* 002 * Copyright 2011 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.workspaces.repository.jcr; 017 018import javax.jcr.Node; 019import javax.jcr.NodeIterator; 020import javax.jcr.RepositoryException; 021 022/** 023 * Node group helper. 024 */ 025public final class NodeGroupHelper 026{ 027 028 /** The maximum children to display per node. */ 029 public static final int MAX_CHILDREN_PER_NODE = 100; 030 031 private NodeGroupHelper() 032 { 033 // Hides the default constructor. 034 } 035 036 /** 037 * Get the node's full path, including virtual path segments. 038 * @param node the node of which to get the path. 039 * @return the computed path. 040 * @throws RepositoryException if a repository error occurs. 041 */ 042 public static String getPathWithGroups(Node node) throws RepositoryException 043 { 044 StringBuffer fullPath = new StringBuffer(); 045 046 // Compute and append all ancestor paths. 047 int depth = node.getDepth(); 048 for (int i = 0; i < depth; i++) 049 { 050 Node ancestor = (Node) node.getAncestor(i); 051 Node ancestorChild = (Node) node.getAncestor(i + 1); 052 053 if (!ancestor.getName().equals("")) 054 { 055 fullPath.append('/').append(ancestor.getName()); 056 057 int index = ancestor.getIndex(); 058 if (index > 1) 059 { 060 fullPath.append('[').append(index).append(']'); 061 } 062 } 063 064 // Append the virtual paths if needed. 065 fullPath.append(getGroupPaths(ancestorChild, MAX_CHILDREN_PER_NODE)); 066 } 067 068 // Append the node path itself. 069 fullPath.append('/').append(node.getName()); 070 071 int index = node.getIndex(); 072 if (index > 1) 073 { 074 fullPath.append('[').append(index).append(']'); 075 } 076 077 return fullPath.toString(); 078 } 079 080 /** 081 * Get the virtual a node's path relative to its parent. 082 * If the parent node has more than a specified node count, "virtual" paths 083 * are added between the parent and the node. 084 * The empty string is returned if the parent doesn't have more nodes than the maximum. 085 * @param node the node to get the virtual path of. 086 * @param maxNodesPerGroup the maximum node per group. 087 * @return the virtual path part of the node in its parent. 088 * @throws RepositoryException if a repository error occurs. 089 */ 090 private static String getGroupPaths(Node node, int maxNodesPerGroup) throws RepositoryException 091 { 092 StringBuilder nodePath = new StringBuilder(); 093 094 NodeIterator children = node.getParent().getNodes(); 095 long childCount = children.getSize(); 096 if (childCount > maxNodesPerGroup) 097 { 098 // Compute virtual path. 099 int level = (int) Math.ceil(Math.log(childCount) / Math.log(maxNodesPerGroup)) - 1; 100 101 int position = 0; 102 boolean found = false; 103 while (children.hasNext() && !found) 104 { 105 if (children.nextNode().isSame(node)) 106 { 107 found = true; 108 } 109 else 110 { 111 position++; 112 } 113 } 114 115 // The position has been found. 116 for (int j = level; j > 0; j--) 117 { 118 int currentGroupCount = (int) Math.pow(maxNodesPerGroup, j); 119 int groupIndex = position / currentGroupCount; 120 121 int startPos = groupIndex * currentGroupCount + 1; 122 int endPos = Math.min(startPos + currentGroupCount - 1, (int) childCount); 123 124 nodePath.append('/').append(startPos).append("...").append(endPos); 125 } 126 } 127 128 return nodePath.toString(); 129 } 130 131}