/******************************************************************************
* HierarchyUtils.java - created by aaronz on Jul 2, 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.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<String> makeNodeIdSet(String encodedNodeIds) {
Set<String> s = new TreeSet<String>();
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<String> nodeIds) {
if (nodeIds == null || nodeIds.size() <= 0) {
return null;
}
// make sure the order written into the database is natural node order
List<String> l = new ArrayList<String>(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;
}
}