Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/action/QueryAction.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/action/QueryAction.java	(revision 31265)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/action/QueryAction.java	(revision 31285)
@@ -11,4 +11,5 @@
 import org.greenstone.gsdl3.util.GSXSLT;
 import org.greenstone.gsdl3.util.UserContext;
+import org.greenstone.gsdl3.util.XMLConverter;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -100,4 +101,5 @@
 			if (request_type.indexOf("d") != -1) {
 			  page_response.appendChild(service_description);
+			  addCollectionsHierarchy(page_response,userContext);
 			}
 			//}
@@ -284,4 +286,55 @@
 		addInterfaceOptions(page_response);
 		return page_response;
+	}
+
+	private void addCollectionsHierarchy(Element page_response, UserContext userContext) {
+		Document doc = page_response.getOwnerDocument();
+		String collectionsHierarchy = "CollectionsHierarchy";
+		if (checkServiceAvailable(userContext, collectionsHierarchy)){
+			Element groupQueryMessage = doc.createElement(GSXML.MESSAGE_ELEM);
+			Element groupQueryRequest = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_PROCESS, collectionsHierarchy, userContext);
+			groupQueryMessage.appendChild(groupQueryRequest);
+			Element groupQueryResult = (Element) this.mr.process(groupQueryMessage);
+			if (groupQueryResult == null){
+				return;
+			}
+			Element groupQueryResponse = (Element) GSXML.getChildByTagName(groupQueryResult, GSXML.RESPONSE_ELEM);
+			if (groupQueryResponse == null){
+				return;
+			}
+			Element hierarchy = (Element) GSXML.getChildByTagName(groupQueryResponse, GSXML.HIERARCHY_ELEM);
+			page_response.appendChild(doc.importNode(hierarchy, true));
+		}
+		
+		
+	}
+
+	private boolean checkServiceAvailable(UserContext userContext, String collectionsHierarchy) {
+		
+		Document doc = XMLConverter.newDOM();
+		Element infoMessage = doc.createElement(GSXML.MESSAGE_ELEM);
+		Element infoRequest = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_DESCRIBE, "", userContext);
+		Element paramList = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
+		infoRequest.appendChild(paramList);
+		GSXML.addParameterToList(paramList, GSXML.SUBSET_PARAM, GSXML.SERVICE_ELEM + GSXML.LIST_MODIFIER);
+		infoMessage.appendChild(infoRequest);
+		Element responseMessage = (Element) this.mr.process(infoMessage);
+		if (responseMessage == null)
+		{
+			logger.error("couldn't query the message router!");
+			return false;
+		}
+		NodeList serviceLists = responseMessage.getElementsByTagName(GSXML.SERVICE_ELEM + GSXML.LIST_MODIFIER);
+		if (serviceLists == null || serviceLists.getLength() == 0){
+			logger.error("No service List in response message from message router!");
+			return false;
+		}
+		Element serviceList = (Element) serviceLists.item(0);
+		Element groupInfoService = GSXML.getNamedElement(serviceList, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, collectionsHierarchy);
+		if (groupInfoService == null){
+			logger.error("service " + collectionsHierarchy + " unavailable");
+			return false;
+		}
+		return true;
 	}
 
@@ -375,3 +428,4 @@
     return true;
   }
+  
 }
Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/CollectionGroups.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/CollectionGroups.java	(revision 31265)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/CollectionGroups.java	(revision 31285)
@@ -30,4 +30,5 @@
 	private static final String GROUP_CONTENT = "GroupCurrentContent";
 	private static final String UNIQUE_COLLECTIONS = "UniqueCollections";
+	private static final String COLLECTIONS_HIERARCHY = "CollectionsHierarchy";
 
 	static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.BerryBasket.class.getName());
@@ -39,5 +40,5 @@
 	}
 
-	String[] _services = { GROUP_CONTENT, UNIQUE_COLLECTIONS };
+	String[] _services = { GROUP_CONTENT, UNIQUE_COLLECTIONS, COLLECTIONS_HIERARCHY };
 
 	public boolean configure(Element info, Element extra_info) {
@@ -56,7 +57,5 @@
 		}
 		// Load group configuration from file
-		readGroupConfiguration();
-
-		return true;
+		return readGroupConfiguration();
 	}
 
@@ -86,5 +85,5 @@
 		groupPath = groupPath.replaceAll("(^/+)|(/+$)", "");
 
-		Element mrCollectionList = getMRCollectionList(userContext);
+		Element mrCollectionList = getAvailableCollectionList(userContext);
 		if (mrCollectionList == null){
 			result.appendChild(doc.createElement(GSXML.COLLECTION_ELEM + GSXML.LIST_MODIFIER));
@@ -92,5 +91,5 @@
 		}
 		//Get current groups and collections
-		Element groupContent = getCurrentContent(groupPath);
+		Element groupContent = getRawCurrentContent(groupPath);
 	
 		//Get ungrouped collection list
@@ -99,12 +98,5 @@
 		// If groupContent is empty return empty collection list
 		if (groupContent == null) {
-			// If config file is broken
-			if (hierarchy == null || groupDesc == null) {
-				//Get ungrouped collection list
-				result.appendChild(doc.importNode(ungroupedCollections, true));
-			} else {
-				//If config is ok, but in this group no any collection or group
-				result.appendChild(doc.createElement(GSXML.COLLECTION_ELEM + GSXML.LIST_MODIFIER));
-			}
+			result.appendChild(doc.createElement(GSXML.COLLECTION_ELEM + GSXML.LIST_MODIFIER));
 			return result;
 		}
@@ -139,12 +131,8 @@
 					Element currentGroup = (Element) currentContent.item(i);
 					String currentGroupName = currentGroup.getAttribute(GSXML.NAME_ATT);
-					//Get group description
-					Element group = getGroupDescription(currentGroupName);
-					//Set position value
-					if (group != null) {
-						group.setAttribute(GSXML.POSITION_ATT, String.valueOf(i));
-						result_group_list.appendChild(doc.importNode(group, true));
-					}
-
+					Element groupDescription = getGroupDescription(currentGroupName);
+					
+					groupDescription.setAttribute(GSXML.POSITION_ATT, String.valueOf(i));
+					result_group_list.appendChild(doc.importNode(groupDescription, true));
 				}
 
@@ -152,5 +140,4 @@
 			//Add ungrouped collections if groupPath /+ or "" or null
 			if (groupPath.isEmpty()) {
-				
 				
 				//Add each ungrouped collection to the collection list in loop
@@ -183,5 +170,5 @@
 		Element resultCollections = doc.createElement(GSXML.COLLECTION_ELEM + GSXML.LIST_MODIFIER);
 		result.appendChild(resultCollections);
-		Element mrCollectionList = getMRCollectionList(userContext);
+		Element mrCollectionList = getAvailableCollectionList(userContext);
 		//Collections from message router check
 		if (mrCollectionList == null){
@@ -218,5 +205,5 @@
 		groups = GSXML.getValue(groupParam).split(",");
 		for (int i = 0; i < groups.length; i++) {
-			Element groupContent = getCurrentContent(groups[i]);
+			Element groupContent = getRawCurrentContent(groups[i]);
 			//If group exists
 			if (groupContent != null) {
@@ -241,16 +228,51 @@
 	}
 	
-	private Element getCurrentContent(String path) {
-
-		if (hierarchy == null || groupDesc == null) {
-			return null;
-		}
-		
-		Document doc = XMLConverter.newDOM();
-		
+	protected Element processCollectionsHierarchy(Element request){
+		
+		Document doc = XMLConverter.newDOM();
+		UserContext userContext = new UserContext(request);
+		// Prepare basic response
+		Element result = GSXML.createBasicResponse(doc, GSXML.SERVICE_TYPE_GROUPINFO);
+		String currentPath = "";
+		Element currentContent = getRawCurrentContent(currentPath);
+		if (currentContent == null){
+			return result;
+		}
+		Element searchableCollectionList = getSearchableCollectionList(userContext);
+		if (searchableCollectionList == null){
+			return result;
+		}
+		
+		//Get ungrouped collection list
+		sanitizeCurrentContent(currentContent, searchableCollectionList);
+		addGroupInfo(currentContent, currentPath);
+		addUngroupedCollections(currentContent, searchableCollectionList);
+		result.appendChild(doc.importNode(currentContent, true));
+		return result;
+	}
+	
+	private void addGroupInfo(Element currentContent, String groupPath) {
+		NodeList groups = GSXML.getChildrenByTagName(currentContent,GSXML.GROUP_ELEM);
+		for (int i=0;i<groups.getLength();i++){
+			Element group = (Element) groups.item(i);
+			String name = group.getAttribute(GSXML.NAME_ATT);
+			String newPath = groupPath + "/" + name; 
+			group.setAttribute(GSXML.PATH_ATT, newPath);
+			Element groupDescription = getGroupDescription(name);
+			Element titleEl = (Element) GSXML.getChildByTagName(groupDescription, GSXML.TITLE_ELEM);
+			String title = titleEl.getTextContent();
+			group.setAttribute(GSXML.TITLE_ELEM, title	);
+			addGroupInfo(group, newPath);
+		}
+		
+	}
+
+	private Element getRawCurrentContent(String path) {
+
 		if (path == null) {
 			 path = "";
 		}
-		
+
+		Document doc = XMLConverter.newDOM();
 		path = path.replaceAll("(/+)", "/");
 		path = path.replaceAll("(^/+)|(/+$)", "");
@@ -259,22 +281,57 @@
 
 		
-		Element currentView = (Element) hierarchy.cloneNode(true);
+		Element currentContent = (Element) hierarchy.cloneNode(true);
 		// Get the current view
 		for (int i = 0; i < pathSteps.length; i++) {
 			if (!pathSteps[i].isEmpty()) {
-				currentView = GSXML.getNamedElement(currentView, GSXML.GROUP_ELEM, GSXML.NAME_ATT, pathSteps[i]);
-				if (currentView == null){
+				currentContent = GSXML.getNamedElement(currentContent, GSXML.GROUP_ELEM, GSXML.NAME_ATT, pathSteps[i]);
+				if (currentContent == null){
 					break;
 				}
 			}
 		}
-		if (currentView == null || !currentView.hasChildNodes()) {
+		if (currentContent == null || !currentContent.hasChildNodes()) {
 			// Return to the main page
 			return null;
 		}
-		return currentView;
-	}
-
-	private void readGroupConfiguration() {
+		return currentContent;
+	}
+	
+	private void sanitizeCurrentContent(Element currentContent, Element checkedCollectionList){
+		if (currentContent == null){
+			return;
+		}
+		NodeList nodes = currentContent.getElementsByTagName(GSXML.COLLECTION_ELEM);
+		for (int i = 0; i < nodes.getLength(); i++) {
+			Element element = (Element) nodes.item(i);
+			String name = element.getAttribute(GSXML.NAME_ATT);
+			Element checkedCollection = GSXML.getNamedElement(checkedCollectionList, GSXML.COLLECTION_ELEM, GSXML.NAME_ATT, name);
+			if (checkedCollection == null) {
+				element.getParentNode().removeChild(element);
+				i--;
+			}
+		}
+	}
+	
+	private void addUngroupedCollections(Element currentContent, Element availableCollections){
+		if (currentContent == null){
+			return;
+		}
+		Document doc = currentContent.getOwnerDocument();
+		NodeList collectionList = availableCollections.getElementsByTagName(GSXML.COLLECTION_ELEM);
+		for (int i = 0; i < collectionList.getLength();i++){
+			Element collection = (Element) collectionList.item(i);
+			String name = collection.getAttribute(GSXML.NAME_ATT);
+			NodeList foundCollection = GSXML.getNamedElements(currentContent, GSXML.COLLECTION_ELEM, GSXML.NAME_ATT, name);
+			if (foundCollection.getLength() == 0){
+				Element ungroupedCollection = doc.createElement(GSXML.COLLECTION_ELEM);
+				ungroupedCollection.setAttribute(GSXML.NAME_ATT, name);
+				currentContent.appendChild(ungroupedCollection);
+			}
+		}
+		
+	}
+
+	private boolean readGroupConfiguration() {
 
 		File configFile = new File(GSFile.groupConfigFile(site_home));
@@ -282,5 +339,5 @@
 		if (!configFile.exists()) {
 			logger.info("Groups config file " + configFile.getPath() + " does not exist.");
-			return;
+			return false;
 		}
 		// Try to read and catch exception if it fails
@@ -301,30 +358,46 @@
 			logger.error("Error occurred while trying to remove emtpy nodes from groupConfig.xml");
 			e.printStackTrace();
+			return false;
 		}  
 		
 		hierarchy = (Element) GSXML.getChildByTagName(content, GSXML.HIERARCHY_ELEM);
 		groupDesc = (Element) GSXML.getChildByTagName(content, GSXML.GROUP_DESC_ELEM);
+		if (hierarchy == null || groupDesc == null){
+			logger.error("Error processing groups configuration. Check groupConfig.xml");
+			return false;
+		}
+		verifyGroupDescription();
+		return true;
+	}
+
+	private void verifyGroupDescription() {
+		Document doc = groupDesc.getOwnerDocument();
+		NodeList groups = hierarchy.getElementsByTagName(GSXML.GROUP_ELEM);
+		for (int i = 0; i < groups.getLength(); i++) {
+			Element group = (Element) groups.item(i); 
+			String name = group.getAttribute(GSXML.NAME_ATT);
+			Element foundDescription = GSXML.getNamedElement(groupDesc, GSXML.GROUP_ELEM, GSXML.NAME_ATT, name);
+			if (foundDescription == null){
+				Element defaultDescription = doc.createElement(GSXML.GROUP_ELEM); 
+				defaultDescription.setAttribute(GSXML.NAME_ATT, name);
+				Element groupTitle = doc.createElement(GSXML.TITLE_ELEM);
+				groupTitle.setTextContent(name);
+				defaultDescription.appendChild(groupTitle);
+				groupDesc.appendChild(defaultDescription);
+			}
+		} 
+		
 	}
 
 	private Element getGroupDescription(String name) {
-		if (groupDesc != null) {
-			Element description = (Element) GSXML.getNamedElement(groupDesc, GSXML.GROUP_ELEM, GSXML.NAME_ATT, name);
-			if (description != null) {
-				return description;
-			}
+		Element description = (Element) GSXML.getNamedElement(groupDesc, GSXML.GROUP_ELEM, GSXML.NAME_ATT, name);
+		if (description == null) {
 			logger.error("GroupDescription is not defined. Check your groupConfig.xml");
-		} 
-			
-		logger.error("No group descriptions found. Check your groupConfig.xml");
-		return null;
+		}
+		return description;
 	}
 
 	private Element getUngroupedCollections(Element mr_collection_list) {
 		
-		if (groupDesc == null || hierarchy == null) {
-			logger.error("No group descriptions in groupConfig.xml. Check your groupConfig.xml");
-			//return mr_collection_list
-			return mr_collection_list;
-		}
 		Document doc = XMLConverter.newDOM();
 		// Create Set
@@ -366,8 +439,4 @@
 	private Element getPathInfo(String path) {
 
-		if (hierarchy == null || groupDesc == null) {
-			return null;
-		}
-		
 		Document doc = XMLConverter.newDOM();
 		
@@ -387,6 +456,6 @@
 					pathStepDescription.setAttribute(GSXML.POSITION_ATT, String.valueOf(i));
 					pathStepDescription.setAttribute(GSXML.PATH_ATT, currentPath);
-					pathInfo.appendChild(doc.importNode(pathStepDescription, true));
-				}
+				}
+				pathInfo.appendChild(doc.importNode(pathStepDescription, true));
 			}
 		}
@@ -394,5 +463,5 @@
 		return pathInfo;
 	}
-	private Element getMRCollectionList(UserContext userContext){
+	private Element getAvailableCollectionList(UserContext userContext){
 		Document doc = XMLConverter.newDOM();
 		// Get the message router info
@@ -415,3 +484,28 @@
 		return mr_collection_list;
 	}
+	private Element getSearchableCollectionList(UserContext userContext){
+		Document doc = XMLConverter.newDOM();
+		Element collectionList = doc.createElement(GSXML.COLLECTION_ELEM + GSXML.LIST_MODIFIER);
+		// Get the message router info
+		Element mr_info_message = doc.createElement(GSXML.MESSAGE_ELEM);
+		Element mr_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_DESCRIBE, "TextQuery" , userContext);
+		mr_info_message.appendChild(mr_request);
+		Element mr_info_response_message = (Element) this.router.process(mr_info_message);
+		if (mr_info_response_message == null) {
+			logger.error(" couldn't query the message router!");
+			return null;
+		}
+		NodeList options = mr_info_response_message.getElementsByTagName(GSXML.PARAM_OPTION_ELEM);
+		for (int i = 0; i < options.getLength(); i++) {
+			Element option = (Element) options.item(i);
+			String name = option.getAttribute(GSXML.NAME_ATT);
+			if (name.equals("all")){
+				continue;
+			}
+			Element collection = doc.createElement(GSXML.COLLECTION_ELEM);
+			collection.setAttribute(GSXML.NAME_ATT, name);
+			collectionList.appendChild(collection);
+		}
+		return collectionList;
+	}
 }
Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/CrossCollectionSearch.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/CrossCollectionSearch.java	(revision 31265)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/CrossCollectionSearch.java	(revision 31285)
@@ -533,6 +533,6 @@
 			groupParamList.appendChild(doc.importNode(GSXML.getNamedElement(paramList, GSXML.PARAM_ELEM, GSXML.NAME_ATT, GSXML.GROUP_ELEM), true));
 			Element groupQueryResult = (Element) this.router.process(groupQueryMessage);
-			Element groupQueryResonse = (Element) GSXML.getChildByTagName(groupQueryResult, GSXML.RESPONSE_ELEM);
-			Element collList = (Element) GSXML.getChildByTagName(groupQueryResonse, GSXML.COLLECTION_ELEM + GSXML.LIST_MODIFIER);
+			Element groupQueryResponse = (Element) GSXML.getChildByTagName(groupQueryResult, GSXML.RESPONSE_ELEM);
+			Element collList = (Element) GSXML.getChildByTagName(groupQueryResponse, GSXML.COLLECTION_ELEM + GSXML.LIST_MODIFIER);
 			NodeList collections = GSXML.getChildrenByTagName(collList, GSXML.COLLECTION_ELEM);
 			collArray = new String[collections.getLength()];
