Index: /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/action/PageAction.java
===================================================================
--- /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/action/PageAction.java	(revision 30539)
+++ /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/action/PageAction.java	(revision 30540)
@@ -26,4 +26,5 @@
 
 	public Node process(Node message_node)
+	
 	{
 		Element message = GSXML.nodeToElement(message_node);
@@ -92,10 +93,21 @@
 	  Document doc = XMLConverter.newDOM();
 		
+
 		UserContext userContext = new UserContext(request);
 		// first, get the message router info
 		Element info_message = doc.createElement(GSXML.MESSAGE_ELEM);
-		Element coll_list_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_DESCRIBE, "", userContext);
-		info_message.appendChild(coll_list_request);
+		Element info_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_DESCRIBE, "", userContext);
+		//Create param list
+		Element param_list_element = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
+		info_request.appendChild(param_list_element);
+		//Describe params without collectionlist. Collectionlist provided by CollectionGroup service
+		GSXML.addParameterToList(param_list_element, GSXML.SUBSET_PARAM, GSXML.CLUSTER_ELEM + GSXML.LIST_MODIFIER);
+		GSXML.addParameterToList(param_list_element, GSXML.SUBSET_PARAM, GSXML.SERVICE_ELEM + GSXML.LIST_MODIFIER);
+		GSXML.addParameterToList(param_list_element, GSXML.SUBSET_PARAM, GSXML.SITE_ELEM + GSXML.LIST_MODIFIER);
+		GSXML.addParameterToList(param_list_element, GSXML.SUBSET_PARAM, GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
+		info_message.appendChild(info_request);
+		//Send request to message router
 		Element info_response_message = (Element) this.mr.process(info_message);
+		//Check if it is not null
 		if (info_response_message == null)
 		{
@@ -103,4 +115,5 @@
 			return null;
 		}
+		//Check if it is not null
 		Element info_response = (Element) GSXML.getChildByTagName(info_response_message, GSXML.RESPONSE_ELEM);
 		if (info_response == null)
@@ -108,4 +121,59 @@
 			logger.error("couldn't query the message router!");
 			return null;
+		}
+		
+		Element resp_service_list = (Element) GSXML.getChildByTagName(info_response, GSXML.SERVICE_ELEM + GSXML.LIST_MODIFIER);
+		
+		if (resp_service_list == null) {
+			logger.error("No services available. Couldn't query the message router!");
+			return null;
+		}
+		Element groupInfoService = GSXML.getNamedElement(resp_service_list, GSXML.SERVICE_ELEM, GSXML.TYPE_ATT,
+				GSXML.SERVICE_TYPE_GROUPINFO);
+		if (groupInfoService != null) {
+			// Prepare request for CollectionGroup service to get current
+			// collections and groups list
+			Element group_info_message = doc.createElement(GSXML.MESSAGE_ELEM);
+			Element group_info_request = GSXML.createBasicRequest(doc, GSXML.TO_ATT,
+					groupInfoService.getAttribute(GSXML.NAME_ATT), userContext);
+			group_info_message.appendChild(group_info_request);
+			//Append group request if exists
+			Element paramList = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
+			if (paramList != null) {
+				group_info_request.appendChild(doc.importNode(paramList, true));
+			}
+			Element group_info_response_message = (Element) this.mr.process(group_info_message);
+			Element group_info_response = (Element) GSXML.getChildByTagName(group_info_response_message,
+					GSXML.RESPONSE_ELEM);
+			Element collection_list = (Element) GSXML.getChildByTagName(group_info_response,
+					GSXML.COLLECTION_ELEM + GSXML.LIST_MODIFIER);
+			// Add Collection List from CollectionGroup Service to response
+			// from message router
+			info_response = (Element) doc.importNode(info_response, true);
+			if (collection_list != null) {
+				info_response.appendChild(doc.importNode(collection_list, true));
+			}
+			Element group_list = (Element) GSXML.getChildByTagName(group_info_response,
+					GSXML.GROUP_ELEM + GSXML.LIST_MODIFIER);
+			if (group_list != null) {
+				info_response.appendChild(doc.importNode(group_list, true));
+			}
+			// Send message to groupInfoType Services
+		} else {
+			// If no service with type SERVICE_TYPE_GROUPINFO could be provided
+			// request message router for all available collections
+			GSXML.addParameterToList(param_list_element, GSXML.SUBSET_PARAM,
+					GSXML.COLLECTION_ELEM + GSXML.LIST_MODIFIER);
+			info_response_message = (Element) this.mr.process(info_message);
+
+			if (info_response_message == null) {
+				logger.error(" couldn't query the message router!");
+				return null;
+			}
+			info_response = (Element) GSXML.getChildByTagName(info_response_message, GSXML.RESPONSE_ELEM);
+			if (info_response == null) {
+				logger.error("couldn't query the message router!");
+				return null;
+			}
 		}
 
@@ -113,5 +181,5 @@
 		// elements but for now, we'll just get it all
 		Element collection_list = (Element) GSXML.getChildByTagName(info_response, GSXML.COLLECTION_ELEM + GSXML.LIST_MODIFIER);
-		logger.debug(GSXML.xmlNodeToString(collection_list));
+		//logger.debug(GSXML.xmlNodeToString(collection_list));
 		if (collection_list != null)
 		{
Index: /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/CollectionGroups.java
===================================================================
--- /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/CollectionGroups.java	(revision 30540)
+++ /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/CollectionGroups.java	(revision 30540)
@@ -0,0 +1,300 @@
+package org.greenstone.gsdl3.service;
+
+import java.io.File;
+import org.apache.log4j.Logger;
+import org.greenstone.gsdl3.util.GSFile;
+import org.greenstone.gsdl3.util.GSXML;
+import org.greenstone.gsdl3.util.UserContext;
+import org.greenstone.gsdl3.util.XMLConverter;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import java.util.Set;
+
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import java.util.HashSet;
+
+public class CollectionGroups extends ServiceRack {
+
+	private Element hierarchy = null;
+	private Element groupDesc = null;
+
+	private static final String GROUP_CONTENT = "GroupCurrentContent";
+
+	static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.BerryBasket.class.getName());
+
+	@Override
+	protected Element getServiceDescription(Document doc, String service, String lang, String subset) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	String[] _services = { GROUP_CONTENT };
+
+	public boolean configure(Element info, Element extra_info) {
+		if (!super.configure(info, extra_info)) {
+			return false;
+		}
+
+		logger.info("Configuring CollectionGroups...");
+		this.config_info = info;
+
+		for (int i = 0; i < _services.length; i++) {
+			Element service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
+			service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_GROUPINFO);
+			service.setAttribute(GSXML.NAME_ATT, _services[i]);
+			this.short_service_info.appendChild(service);
+		}
+		// Load group configuration from file
+		readGroupConfiguration();
+
+		return true;
+	}
+
+	protected Element processGroupCurrentContent(Element request) {
+
+		Document doc = XMLConverter.newDOM();
+
+		UserContext userContext = new UserContext(request);
+
+		// Get param list from request
+		Element paramList = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
+		// Set default group path (main page)
+		String groupPath = "";
+		// If param list not null and group param exists extract value and
+		// override groupPath variable
+		if (paramList != null) {
+			Element paramGroup = GSXML.getNamedElement(paramList, GSXML.PARAM_ELEM, GSXML.NAME_ATT, GSXML.GROUP_ELEM);
+			if (paramGroup != null) {
+				groupPath = paramGroup.getAttribute(GSXML.VALUE_ATT);
+			}
+		}
+		//Remove leading, ending / and dupliclated /
+		groupPath = groupPath.replaceAll("(/+)", "/");
+		groupPath = groupPath.replaceAll("(^/+)|(/+$)", "");
+
+		// Get the message router info
+		Element mr_info_message = doc.createElement(GSXML.MESSAGE_ELEM);
+		Element mr_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_DESCRIBE, "", 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;
+		}
+		Element mr_info_response = (Element) GSXML.getChildByTagName(mr_info_response_message, GSXML.RESPONSE_ELEM);
+		if (mr_info_response == null) {
+			logger.error("couldn't query the message router!");
+			return null;
+		}
+
+		Element mr_collection_list = (Element) GSXML.getChildByTagName(mr_info_response,
+				GSXML.COLLECTION_ELEM + GSXML.LIST_MODIFIER);
+		//Get current groups and collections
+		Element groupContent = getCurrentContent(groupPath);
+	
+		//Get ungrouped collection list
+		Element ungroupedCollections = getUngroupedCollections(mr_collection_list);
+		
+		// Prepare basic response
+		Element result = GSXML.createBasicResponse(doc, GSXML.SERVICE_TYPE_GROUPINFO);
+
+		// 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));
+			}
+			return result;
+		}
+		NodeList currentContent = groupContent.getChildNodes();
+		if (currentContent != null && currentContent.getLength() > 0) {
+			// Create CollectionList element in response
+			Element result_collection_list = doc.createElement(GSXML.COLLECTION_ELEM + GSXML.LIST_MODIFIER);
+			result.appendChild(result_collection_list);
+			Element result_group_list = doc.createElement(GSXML.GROUP_ELEM + GSXML.LIST_MODIFIER);
+			result.appendChild(result_group_list);
+			// Iterate over collections from current view
+			// i represents current position in groupConfig.xml
+			int i;
+			for (i=0; i < currentContent.getLength(); i++) {
+				//logger.warn("NODE CuR Content" + GSXML.xmlNodeToString(currentContent.item(i)));
+				
+				if (currentContent.item(i).getNodeName() == GSXML.COLLECTION_ELEM) {
+					
+					Element collection = (Element) currentContent.item(i);
+					String collection_name = collection.getAttribute(GSXML.NAME_ATT);
+					// Check whether collection from current view exists in message router response
+					Element checkedCollection = GSXML.getNamedElement(mr_collection_list, GSXML.COLLECTION_ELEM,GSXML.NAME_ATT, collection_name);
+					//Set position value
+					checkedCollection.setAttribute(GSXML.POSITION_ATT, String.valueOf(i));
+					if (checkedCollection != null) {
+						// Add collection to response
+						result_collection_list.appendChild(doc.importNode(checkedCollection, true));
+					}
+					
+					//Iterate over groups in current view
+				} else if (currentContent.item(i).getNodeName() == GSXML.GROUP_ELEM) {
+					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));
+					}
+
+				}
+
+			}
+			//Add ungrouped collections if groupPath /+ or "" or null
+			if (groupPath.isEmpty()) {
+				
+				
+				//Add each ungrouped collection to the collection list in loop
+				NodeList ungroupedCollectionNodes = GSXML.getChildrenByTagName(ungroupedCollections, GSXML.COLLECTION_ATT);
+				if (ungroupedCollectionNodes != null) {
+					for (int j = 0; j < ungroupedCollectionNodes.getLength(); j++) {
+						//logger.warn("UNGROUPED COLL ELEM" + GSXML.xmlNodeToString(ungroupedCollections).intern());
+						Element ungroupedCollection = (Element) doc.importNode(ungroupedCollectionNodes.item(j), true);
+						ungroupedCollection.setAttribute(GSXML.POSITION_ATT, String.valueOf(i++));
+						result_collection_list.appendChild(ungroupedCollection);
+					}
+				}
+				
+			}
+			
+			
+
+		}
+
+		return result;
+	}
+
+	private Element getCurrentContent(String path) {
+
+		if (hierarchy == null || groupDesc == null) {
+			return null;
+		}
+		
+		Document doc = XMLConverter.newDOM();
+		
+		if (path == null) {
+			 path = "";
+		}
+		String[] pathSteps = path.split("/");
+
+		
+		Element currentView = (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 || !currentView.hasChildNodes()) {
+			// Return to the main page
+			return null;
+		}
+		return currentView;
+	}
+
+	private void readGroupConfiguration() {
+
+		File configFile = new File(GSFile.groupConfigFile(site_home));
+		//
+		if (!configFile.exists()) {
+			logger.error("Groups config file " + configFile.getPath() + " does not exists");
+		}
+		// Try to read and catch exception if it fails
+		Document doc = XMLConverter.getDOM(configFile);
+		Element content = doc.getDocumentElement();
+		
+		// XPath to find empty text nodes.
+		try {
+			XPathFactory xpathFactory = XPathFactory.newInstance();
+			XPathExpression xpathExp = xpathFactory.newXPath().compile("//text()[normalize-space(.) = '']");  
+			NodeList emptyTextNodes = (NodeList) xpathExp.evaluate(doc, XPathConstants.NODESET);
+			for (int i = 0; i < emptyTextNodes.getLength(); i++) {
+			    Node emptyTextNode = emptyTextNodes.item(i);
+			    emptyTextNode.getParentNode().removeChild(emptyTextNode);
+			}
+			
+		} catch (XPathExpressionException e) {
+			logger.error("Error occurred while trying to remove emtpy nodes from groupConfig.xml");
+			e.printStackTrace();
+		}  
+		
+		hierarchy = (Element) GSXML.getChildByTagName(content, GSXML.HIERARCHY_ELEM);
+		groupDesc = (Element) GSXML.getChildByTagName(content, GSXML.GROUP_DESC_ELEM);
+	}
+
+	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;
+			}
+			logger.error("GroupDescription is not defined. Check your groupConfig.xml");
+		} 
+			
+		logger.error("No group descriptions found. Check your groupConfig.xml");
+		return null;
+	}
+
+	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
+		Set<String> hierarchy_unique_collections = new HashSet<String>();
+		// Element hierarchyCollections = doc.createElement("coll_list");
+		// Get collection nodes
+		
+		NodeList hierarchy_all_collection_list = hierarchy.getElementsByTagName(GSXML.COLLECTION_ELEM);
+		// Save hierarchy collection names to Hashset
+		for (int i = 0; i < hierarchy_all_collection_list.getLength(); i++) {
+			Element collection_element = (Element) hierarchy_all_collection_list.item(i);
+			hierarchy_unique_collections.add(collection_element.getAttribute(GSXML.NAME_ATT));
+		}
+		// Save available by message router collection names to Hashset
+		Set<String> mr_collections = new HashSet<String>();
+		NodeList mr_coll_list = mr_collection_list.getElementsByTagName(GSXML.COLLECTION_ELEM);
+
+		for (int i = 0; i < mr_coll_list.getLength(); i++) {
+			Element collection_element = (Element) mr_coll_list.item(i);
+			mr_collections.add(collection_element.getAttribute(GSXML.NAME_ATT));
+		}
+		//Save collections available by message router and not existed in hierarchy to ungrouped collections set
+		Set<String> ungrouped_collections = new HashSet<String>();
+		for (String string : mr_collections) {
+			if (!hierarchy_unique_collections.contains(string)){
+				ungrouped_collections.add(string);
+			}
+		}
+		//Output
+		Element result = doc.createElement(GSXML.COLLECTION_ELEM + GSXML.LIST_MODIFIER);
+		for (String name : ungrouped_collections) {
+			Element collection = doc.createElement(GSXML.COLLECTION_ELEM);
+			collection.setAttribute(GSXML.NAME_ATT, name);
+			result.appendChild(collection);
+		}
+		return result;
+
+	}
+
+}
Index: /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/GSFile.java
===================================================================
--- /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/GSFile.java	(revision 30539)
+++ /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/GSFile.java	(revision 30540)
@@ -54,4 +54,18 @@
 
 	}
+	
+	/** site config file path */
+	static public String groupConfigFile(String site_home)
+	{
+		return site_home + File.separatorChar + "groupConfig.xml";
+
+	}
+	
+	/** site images file path */
+	static public String imagesFilePath(String site_home)
+	{
+		return site_home + File.separatorChar + "images";
+
+	}
 
 	/** interface config file path */
Index: /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/GSXML.java
===================================================================
--- /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/GSXML.java	(revision 30539)
+++ /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/GSXML.java	(revision 30540)
@@ -233,4 +233,5 @@
 	public static final String SERVICE_TYPE_RETRIEVE = "retrieve";
 	public static final String SERVICE_TYPE_BROWSE = "browse";
+	public static final String SERVICE_TYPE_GROUPINFO = "groupinfo";
 	public static final String SERVICE_TYPE_APPLET = "applet";
 	public static final String SERVICE_TYPE_PROCESS = "process";
@@ -306,4 +307,13 @@
 	public static final String UTIL_NAMESPACE = "xalan://org.greenstone.gsdl3.util.XSLTUtil";
 
+	//Groups configuration
+	public static final String HIERARCHY_ELEM = "hierarchy";
+	public static final String GROUP_DESC_ELEM = "groupDescriptions";
+	public static final String TITLE_ELEM = "title";
+	public static final String DESCRIPTION_ELEM = "description";
+	public static final String SHORT_DESCRIPTION_ELEM = "shortDescription";
+	public static final String BACKGROUND_IMAGE_ELEM = "backgroundImage";
+	public static final String POSITION_ATT = "position";
+	
 	/**
 	 * takes a list of elements, and returns an array of strings of the values
Index: /main/trunk/greenstone3/web/interfaces/default/style/core.css
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default/style/core.css	(revision 30539)
+++ /main/trunk/greenstone3/web/interfaces/default/style/core.css	(revision 30540)
@@ -286,4 +286,26 @@
 }
 
+#groupLinks a img{
+        display: block;
+        float: left;
+        border: 1px solid #888;
+        margin: 0 20px 20px 0;
+        font-size: 150%;
+        color: #444;
+        text-decoration: none;
+        height:60px;
+}
+
+.groupLink {
+	display: block;
+	float: left;
+	border: 1px solid #888;
+	margin: 0 20px 20px 0;
+	font-size: 150%;
+	color: #444;
+	text-decoration: none;
+	min-width: 200px;
+	text-align:center;
+}
 .collectionLink {
 	display: block;
@@ -302,7 +324,15 @@
 }
 
+.groupLinkText {
+        padding: 15px 15px 10px;
+}
+
 /* some text should not be rendered as it is just there for search engines */
 #collectionLinks a b {
 	display: none;
+}
+
+#groupLinks a b {
+        display: none;
 }
 
Index: /main/trunk/greenstone3/web/interfaces/default/transform/gslib.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default/transform/gslib.xsl	(revision 30539)
+++ /main/trunk/greenstone3/web/interfaces/default/transform/gslib.xsl	(revision 30540)
@@ -199,4 +199,29 @@
       </input>
     </form>
+  </xsl:template>
+  
+  <xsl:template name="groupLinkWithImage">
+    <xsl:variable name="desc"><xsl:value-of select="description"/></xsl:variable>
+    <xsl:variable name="group_href"><xsl:value-of select="$library_name"/>?a=p&amp;sa=home&amp;group=<xsl:value-of select="/page/pageRequest/paramList/param[@name='group']/@value"/>/<xsl:value-of select="@name"/></xsl:variable>
+    <xsl:choose>
+      <xsl:when test="backgroundImage">
+        <a href="{$group_href}" title="{$desc}">
+          <img class="groupLinkImage">
+            <xsl:attribute name="alt"><xsl:value-of select="displayItem[@name='name']"/></xsl:attribute>
+            <xsl:attribute name="src">sites/<xsl:value-of select="$site_name"/>/images/<xsl:value-of select="backgroundImage"/></xsl:attribute>
+          </img>
+        </a>
+      </xsl:when>
+      <xsl:otherwise>
+        <a href="{$group_href}" title="{$desc}">
+          <div class="groupLink ui-corner-all">
+			<div class="groupLinkText ui-widget-content ui-corner-top">
+				<xsl:value-of select="title"/>
+			</div>
+			<div style="height:15px;" class="ui-state-default ui-corner-bottom"><xsl:text> </xsl:text></div>
+          </div>
+        </a>
+      </xsl:otherwise>
+    </xsl:choose>
   </xsl:template>
   
Index: /main/trunk/greenstone3/web/interfaces/default/transform/pages/home.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default/transform/pages/home.xsl	(revision 30539)
+++ /main/trunk/greenstone3/web/interfaces/default/transform/pages/home.xsl	(revision 30540)
@@ -15,5 +15,9 @@
 
 	<!-- set page breadcrumbs -->
-	<xsl:template name="breadcrumbs"></xsl:template>
+	<xsl:template name="breadcrumbs">
+		<xsl:if test="/page/pageRequest/paramList/param[@name='group']">
+			<gslib:siteLink/>
+		</xsl:if>
+	</xsl:template>
 
 	<!-- the page content -->
@@ -26,6 +30,14 @@
 		<h2><gslib:selectACollectionTextBar/></h2>
 
-		<xsl:call-template name="collectionLinks"/>
-
+		<xsl:for-each select="collectionList/collection|groupList/group">
+                	<xsl:sort select="@position"/>
+			<xsl:if test="name() = 'collection'">
+                                <gslib:collectionLinkWithImage/>
+			</xsl:if>
+			<xsl:if test="name() = 'group'">
+                                <gslib:groupLinkWithImage/>
+			</xsl:if>			
+                </xsl:for-each>
+	
 	        <div style="clear: both; padding-top: 4px; padding-bottom: 4px;"><hr/></div>
 
@@ -43,4 +55,18 @@
 	</xsl:template>
 
+	<xsl:template name="groupLinks">
+		<div id="groupLinks">
+			<!-- <xsl:if test="count(groupList/group) = 0">
+				<xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'home.no_collections')"/>
+				<br/>
+			</xsl:if>
+			-->
+			<xsl:for-each select="groupList/group">
+				<gslib:groupLinkWithImage/>
+			</xsl:for-each>
+			<br class="clear"/>
+		</div>
+	</xsl:template>
+	
 	<xsl:template name="collectionLinks">
 		<div id="collectionLinks">
Index: /main/trunk/greenstone3/web/sites/localsite/groupConfig.xml
===================================================================
--- /main/trunk/greenstone3/web/sites/localsite/groupConfig.xml	(revision 30540)
+++ /main/trunk/greenstone3/web/sites/localsite/groupConfig.xml	(revision 30540)
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<groupConfig>
+		
+	<hierarchy>
+<!--	
+		<group name="group2">
+			<collection name="solr-jdbm-demo" />
+
+		</group>
+		<group name="group1">
+			
+			<group name="group3">
+				<collection name="solr-jdbm-demo" />
+				<group name="group1">
+					<collection name="solr-jdbm-demo" />
+					<group name="group1">
+
+					</group>
+				</group>
+			</group>
+		</group>
+		<collection name="test-webeditor" />
+-->	
+	</hierarchy>
+	<groupDescriptions>
+<!--	
+		<group name="group1">
+			<title>Group of collections</title>
+			<description>some description</description>
+			<shortDescription>Short description</shortDescription>
+			
+		</group>
+		<group name="group2">
+			<title>Group 2 of collections</title>
+			<description>second full description</description>
+			<shortDescription>second short description</shortDescription>
+			
+		</group>
+		<group name="group3">
+			<title>Group 3 of collections</title>
+			<description>3 full description</description>
+			<shortDescription>3 short description</shortDescription>
+			<backgroundImage>Group3.jpg</backgroundImage>
+		</group>
+-->	
+	</groupDescriptions>
+</groupConfig>
Index: /main/trunk/greenstone3/web/sites/localsite/siteConfig.xml
===================================================================
--- /main/trunk/greenstone3/web/sites/localsite/siteConfig.xml	(revision 30539)
+++ /main/trunk/greenstone3/web/sites/localsite/siteConfig.xml	(revision 30540)
@@ -12,4 +12,5 @@
 		
 		<serviceRack name="ArchiveIO"/>
+		<serviceRack name="CollectionGroups"/>
 		<serviceRack name="DocumentMaker"/>
 		<serviceRack name="DocXMLUtil"/>
