Commit 74dff134 authored by Matt Tucker's avatar Matt Tucker Committed by matt

Refactored admin console framework.


git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@497 b35dd754-fafc-0310-a699-88a17e54d16e
parent 89c34392
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/i18n" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/i18n" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/java" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" /> <excludeFolder url="file://$MODULE_DIR$/target" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
......
...@@ -15,6 +15,7 @@ import org.jivesoftware.util.ClassUtils; ...@@ -15,6 +15,7 @@ import org.jivesoftware.util.ClassUtils;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.dom4j.Document; import org.dom4j.Document;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.DocumentFactory;
import org.dom4j.io.SAXReader; import org.dom4j.io.SAXReader;
import java.util.*; import java.util.*;
...@@ -22,32 +23,27 @@ import java.io.InputStream; ...@@ -22,32 +23,27 @@ import java.io.InputStream;
import java.net.URL; import java.net.URL;
/** /**
* <p>A model for admin tab and sidebar info. This class loads in xml definitions of the data and * A model for admin tab and sidebar info. This class loads in xml definitions of the data and
* produces an in-memory model. There is an internal class, {@link Item} which is the main part * produces an in-memory model.<p>
* of the model. Items hold info like name, id, url and description as well as an arbritrary number
* of sub items. Based on this we can make a tree model of the data.</p>
* *
* <p>This class loads its data from the <tt>admin-sidebar.xml</tt> file which is assumed to be in * This class loads its data from the <tt>admin-sidebar.xml</tt> file which is assumed to be in
* the main application jar file. In addition, it will load files from * the main application jar file. In addition, it will load files from
* <tt>META-INF/admin-sidebar.xml</tt> if they're found. This allows developers to extend the * <tt>META-INF/admin-sidebar.xml</tt> if they're found. This allows developers to extend the
* functionality of the admin console to provide more options. See the main * functionality of the admin console to provide more options. See the main
* <tt>admin-sidebar.xml</tt> file for documentation of its format.</p> * <tt>admin-sidebar.xml</tt> file for documentation of its format.<p>
*
* <p>Note: IDs in the XML file must be unique because an internal mapping is kept of IDs to
* nodes.</p>
*/ */
public class AdminConsole { public class AdminConsole {
private static Map<String,Item> items; private static Element coreModel;
private static String appName; private static List<Element> overrideModels;
private static String logoImage; private static Element generatedModel;
static { static {
init(); init();
} }
private static void init() { private static void init() {
items = Collections.synchronizedMap(new LinkedHashMap<String,Item>()); overrideModels = new ArrayList<Element>();
load(); load();
} }
...@@ -61,10 +57,10 @@ public class AdminConsole { ...@@ -61,10 +57,10 @@ public class AdminConsole {
* @param in the XML input stream. * @param in the XML input stream.
* @throws Exception if an error occurs when parsing the XML or adding it to the model. * @throws Exception if an error occurs when parsing the XML or adding it to the model.
*/ */
public static void addXMLSource(InputStream in) throws Exception { public static void addModel(InputStream in) throws Exception {
SAXReader saxReader = new SAXReader(); SAXReader saxReader = new SAXReader();
Document doc = saxReader.read(in); Document doc = saxReader.read(in);
addXMLSource((Element)doc.selectSingleNode("/adminconsole")); addModel((Element)doc.selectSingleNode("/adminconsole"));
} }
/** /**
...@@ -73,276 +69,60 @@ public class AdminConsole { ...@@ -73,276 +69,60 @@ public class AdminConsole {
* @param element the Element * @param element the Element
* @throws Exception if an error occurs. * @throws Exception if an error occurs.
*/ */
public static void addXMLSource(Element element) throws Exception { public static void addModel(Element element) throws Exception {
addToModel(element); overrideModels.add(element);
rebuildModel();
} }
/** /**
* Returns the name of the application. * Returns the name of the application.
*/ */
public static String getAppName() { public static String getAppName() {
return appName; Element appName = (Element)generatedModel.selectSingleNode("/adminconsole/global/appname");
if (appName != null) {
return appName.getText();
}
else {
return null;
}
} }
/** /**
* Returns the URL (relative or absolute) of the main logo image for the admin console. * Returns the URL (relative or absolute) of the main logo image for the admin console.
*/ */
public static String getLogoImage() { public static String getLogoImage() {
return logoImage; Element globalLogoImage = (Element)generatedModel.selectSingleNode(
} "/adminconsole/global/logo-image");
if (globalLogoImage != null) {
/** return globalLogoImage.getText();
* Returns all root items. Getting the iterator from this collection returns
* all root items (should be used as tabs in the admin tool).
*
* @return a collection of all items - the root items are returned by calling the
* <tt>iterator()</tt> method.
*/
public static Collection<Item> getItems() {
List<Item> rootItems = new ArrayList<Item>();
for (Item i : items.values()) {
if (i.getParent() == null) {
rootItems.add(i);
}
} }
return rootItems; else {
}
/**
* Returns an item given its ID or <tt>null</tt> if it can't be found.
*
* @param id the ID of the item.
* @return an item given its ID or <tt>null</tt> if it can't be found.
*/
public static Item getItem(String id) {
return items.get(id);
}
/**
* Returns the root item given a child item. In other words, a lookup is done on the ID for
* the corresponding item - that item is assumed to be a leaf and this method returns the
* root ancestor of it.
*
* @param id the ID of the child item.
* @return the root ancestor of the specified child item.
*/
public static Item getRootByChildID(String id) {
if (id == null) {
return null; return null;
} }
Item child = getItem(id);
Item root = null;
if (child != null) {
Item parent = child.getParent();
root = parent;
while (parent != null) {
parent = parent.getParent();
if (parent != null) {
root = parent;
}
}
}
return root;
} }
/** /**
* Returns <tt>true</tt> if the given item is a sub-menu item. * Returns the model. The model should be considered read-only.
* *
* @param item the item to test. * @return the model.
* @return <tt>true</tt> if the given item is a sub-menu item, <tt>false</tt> otherwise.
*/
public static boolean isSubMenItem(Item item) {
int parentCount = 0;
Item parent = item.getParent();
while (parent != null) {
parentCount++;
parent = parent.getParent();
}
return parentCount >= 3;
}
/**
* Returns the ID of the page ID associated with this sub page ID.
* @param subPageID the subPageID to use to look up the page ID.
* @return the associated pageID or <tt>null</tt> if it can't be found.
*/ */
public static String lookupPageID(String subPageID) { public static Element getModel() {
String pageID = null; return generatedModel;
Item item = getItem(subPageID);
if (item != null) {
Item parent = item.getParent();
if (parent != null) {
parent = parent.getParent();
if (parent != null) {
pageID = parent.getId();
}
}
}
return pageID;
} }
/** /**
* A simple class to model an item. Each item has attributes used by the admin console to * Convenience method to select an element from the model by its ID. If an
* display it like ID, name, URL and description. Also, from each item you can get its parent * element with a matching ID is not found, <tt>null</tt> will be returned.
* (because an Item goes in a tree structure) and any children items it has. *
* @param id the ID.
* @return the element.
*/ */
public static class Item { public static Element getElemnetByID(String id) {
return (Element)generatedModel.selectSingleNode("//item[@id='" + id + "']");
private String id;
private String name;
private String description;
private String url;
private boolean active;
private Map<String,Item> items;
private Item parent;
private static int idSeq = 0;
/**
* Creates a new item given its main attributes.
*/
public Item(String id, String name, String description, String url) {
this.id = id;
this.name = name;
this.description = description;
this.url = url;
init();
}
/**
* Creates a new item given its main attributes and the parent item (this helps set up
* the tree structure).
*/
public Item(String id, String name, String description, String url, Item parent) {
this.id = id;
this.name = name;
this.description = description;
this.url = url;
this.parent = parent;
init();
}
private void init() {
items = Collections.synchronizedMap(new LinkedHashMap<String,Item>());
if (id == null) {
id = String.valueOf(idSeq++);
}
}
/**
* Returns the ID of the item.
*/
public String getId() {
return id;
}
/**
* Returns the name of the item - this is the display name.
*/
public String getName() {
return name;
}
/**
* Sets the name.
*/
void setName(String name) {
this.name = name;
}
/**
* Returns the description of the item.
*/
public String getDescription() {
return description;
}
/**
* Sets the description.
*/
void setDescription(String description) {
this.description = description;
}
/**
* Returns the URL for this item.
*/
public String getUrl() {
return url;
}
/**
* Sets the URL for this item.
*/
public void setUrl(String url) {
this.url = url;
}
/**
* Returns true if this items is active - in the admin console this would mean it's selected.
*/
public boolean isActive() {
return active;
}
/**
* Sets the item as active - in the admin console this would mean it's selected.
*/
public void setActive(boolean active) {
this.active = active;
}
/**
* Returns the parent item or <tt>null</tt> if this is a root item.
*/
public Item getParent() {
return parent;
}
/**
* Sets the parent item.
*/
public void setParent(Item parent) {
this.parent = parent;
}
public void addItem(Item item) {
items.put(item.getId(), item);
}
/**
* Returns the items as a collection. Use the Collection API to get/set/remove items.
*/
public Collection<Item> getItems() {
return items.values();
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if (!(o instanceof Item)) {
return false;
}
Item i = (Item) o;
if (id == null || !id.equals(i.id)) {
return false;
}
return true;
}
/**
* Returns the ID of the item.
*/
public String toString() {
return id;
}
} }
private static void load() { private static void load() {
// Load the admin-sidebar.xml file from the jiveforums.jar file: // Load the core model as the admin-sidebar.xml file from the classpath.
InputStream in = ClassUtils.getResourceAsStream("/admin-sidebar.xml"); InputStream in = ClassUtils.getResourceAsStream("/admin-sidebar.xml");
if (in == null) { if (in == null) {
Log.error("Failed to load admin-sidebar.xml file from Jive Messenger classes - admin " Log.error("Failed to load admin-sidebar.xml file from Jive Messenger classes - admin "
...@@ -350,7 +130,9 @@ public class AdminConsole { ...@@ -350,7 +130,9 @@ public class AdminConsole {
return; return;
} }
try { try {
addXMLSource(in); SAXReader saxReader = new SAXReader();
Document doc = saxReader.read(in);
coreModel = (Element)doc.selectSingleNode("/adminconsole");
} }
catch (Exception e) { catch (Exception e) {
Log.error("Failure when parsing main admin-sidebar.xml file", e); Log.error("Failure when parsing main admin-sidebar.xml file", e);
...@@ -369,12 +151,14 @@ public class AdminConsole { ...@@ -369,12 +151,14 @@ public class AdminConsole {
Enumeration e = classLoaders[i].getResources("/META-INF/admin-sidebar.xml"); Enumeration e = classLoaders[i].getResources("/META-INF/admin-sidebar.xml");
while (e.hasMoreElements()) { while (e.hasMoreElements()) {
url = (URL)e.nextElement(); url = (URL)e.nextElement();
in = url.openStream();
addXMLSource(in);
try { try {
in.close(); in = url.openStream();
addModel(in);
}
finally {
try { if (in != null) { in.close(); } }
catch (Exception ignored) {}
} }
catch (Exception ignored) {}
} }
} }
} }
...@@ -386,90 +170,115 @@ public class AdminConsole { ...@@ -386,90 +170,115 @@ public class AdminConsole {
Log.warn(msg, e); Log.warn(msg, e);
} }
} }
rebuildModel();
} }
private static void addToModel(Element element) throws Exception { /**
// Set any global properties * Rebuilds the generated model.
Element globalEl = (Element)element.selectSingleNode("/adminconsole/global/appname"); */
if (globalEl != null) { private static void rebuildModel() {
appName = globalEl.getText(); Document doc = DocumentFactory.getInstance().createDocument();
} generatedModel = coreModel.createCopy();
Element globalLogoImageEl = (Element)element.selectSingleNode( doc.add(generatedModel);
"/adminconsole/global/logo-image");
if (globalLogoImageEl != null) { // Add in all overrides.
logoImage = globalLogoImageEl.getText(); for (Element element : overrideModels) {
// See if global settings are overriden.
Element appName = (Element)element.selectSingleNode("/adminconsole/global/appname");
if (appName != null) {
Element existingAppName = (Element)generatedModel.selectSingleNode(
"/adminconsole/global/appname");
existingAppName.setText(appName.getText());
}
Element appLogoImage = (Element)element.selectSingleNode("/adminconsole/global/logo-image");
if (appLogoImage != null) {
Element existingLogoImage = (Element)generatedModel.selectSingleNode(
"/adminconsole/global/logo-image");
existingLogoImage.setText(appLogoImage.getText());
}
// Tabs
for (Iterator i=element.selectNodes("//tab").iterator(); i.hasNext(); ) {
Element tab = (Element)i.next();
String id = tab.attributeValue("id");
Element existingTab = getElemnetByID(id);
// Simple case, there is no existing tab with the same id.
if (existingTab == null) {
generatedModel.add(tab.createCopy());
}
// More complex case -- a tab with the same id already exists.
// In this case, we have to overrite only the difference between
// the two elements.
else {
overrideTab(existingTab, tab);
}
}
} }
}
// Get all children of the 'tabs' element - should be 'tab' items: private static void overrideTab(Element tab, Element overrideTab) {
List tabs = element.elements("tab"); // Override name, url, description.
for (int i=0; i<tabs.size(); i++) { tab.addAttribute("name", overrideTab.attributeValue("name"));
Element tab = (Element)tabs.get(i); tab.addAttribute("url", overrideTab.attributeValue("url"));
tab.addAttribute("description", overrideTab.attributeValue("description"));
// Create a new top level item with data from the xml file: // Override sidebar items.
String id = tab.attributeValue("id"); for (Iterator i=overrideTab.elementIterator(); i.hasNext(); ) {
String name = tab.attributeValue("name"); Element sidebar = (Element)i.next();
String description = tab.attributeValue("description"); String id = sidebar.attributeValue("id");
Item item = new Item(id, name, description, null); Element existingSidebar = getElemnetByID(id);
// Add that item to the item collection // Simple case, there is no existing sidebar with the same id.
items.put(id, item); if (existingSidebar == null) {
tab.add(sidebar.createCopy());
// Delve down into this item's sidebars - build up a model of these then add into }
// the item above. // More complex case -- a sidebar with the same id already exists.
List sidebars = tab.elements("sidebar"); // In this case, we have to overrite only the difference between
for (int j=0; j<sidebars.size(); j++) { // the two elements.
Element sidebar = (Element)sidebars.get(j); else {
overrideSidebar(existingSidebar, sidebar);
name = sidebar.attributeValue("name");
// Create a new item, set its name
Item sidebarItem = new Item(null, name, null, null);
// Get all items of this sidebar:
List subitems = sidebar.elements("item");
for (int k=0; k<subitems.size(); k++) {
Element subitem = (Element)subitems.get(k);
// Get the id, name, descr and url attributes:
String subID = subitem.attributeValue("id");
String subName = subitem.attributeValue("name");
String subDescr = subitem.attributeValue("description");
String subURL = subitem.attributeValue("url");
// Build an item with this, add it to the subItem we made above
Item kItem = new Item(subID, subName, subDescr, subURL, sidebarItem);
items.put(kItem.getId(), kItem);
sidebarItem.addItem(kItem);
// Build any sub-sub menus:
subAddtoModel(subitem, kItem);
// If this is the first item, set the root menu item's URL as this URL:
if (j==0 && k == 0) {
item.setUrl(subURL);
}
}
// Add the subItem to the item created above
sidebarItem.setParent(item);
items.put(sidebarItem.getId(), sidebarItem);
item.addItem(sidebarItem);
} }
} }
} }
private static void subAddtoModel(Element parentElement, Item parentItem) { private static void overrideSidebar(Element sidebar, Element overrideSidebar) {
// Override name.
sidebar.addAttribute("name", overrideSidebar.attributeValue("name"));
// Override entries.
for (Iterator i=overrideSidebar.elementIterator(); i.hasNext(); ) {
Element entry = (Element)i.next();
String id = sidebar.attributeValue("id");
Element existingEntry = getElemnetByID(id);
// Simple case, there is no existing sidebar with the same id.
if (existingEntry == null) {
sidebar.add(entry.createCopy());
}
// More complex case -- a sidebar with the same id already exists.
// In this case, we have to overrite only the difference between
// the two elements.
else {
overrideEntry(existingEntry, entry);
}
}
}
List subsidebars = parentElement.elements("subsidebar"); private static void overrideEntry(Element entry, Element overrideEntry) {
for (int i=0; i<subsidebars.size(); i++) { // Override name.
Element subsidebar = (Element)subsidebars.get(i); entry.addAttribute("name", overrideEntry.attributeValue("name"));
String subsidebarName = subsidebar.attributeValue("name"); entry.addAttribute("url", overrideEntry.attributeValue("url"));
Item subsidebarItem = new Item(null, subsidebarName, null, null, parentItem); entry.addAttribute("description", overrideEntry.attributeValue("description"));
// Get the items under it // Override any sidebars contained in the entry.
List subitems = subsidebar.elements("item"); for (Iterator i=overrideEntry.elementIterator(); i.hasNext(); ) {
for (int j=0; j<subitems.size(); j++) { Element sidebar = (Element)i.next();
Element item = (Element)subitems.get(j); String id = sidebar.attributeValue("id");
String id = item.attributeValue("id"); Element existingSidebar = getElemnetByID(id);
String name = item.attributeValue("name"); // Simple case, there is no existing sidebar with the same id.
String url = item.attributeValue("url"); if (existingSidebar == null) {
String descr = item.attributeValue("description"); entry.add(sidebar.createCopy());
Item newItem = new Item(id, name, descr, url, subsidebarItem); }
subsidebarItem.addItem(newItem); // More complex case -- a sidebar with the same id already exists.
items.put(id, newItem); // In this case, we have to overrite only the difference between
// the two elements.
else {
overrideSidebar(existingSidebar, sidebar);
} }
parentItem.addItem(subsidebarItem);
} }
} }
...@@ -483,9 +292,4 @@ public class AdminConsole { ...@@ -483,9 +292,4 @@ public class AdminConsole {
classLoaders[2] = ClassLoader.getSystemClassLoader(); classLoaders[2] = ClassLoader.getSystemClassLoader();
return classLoaders; return classLoaders;
} }
}
// Called by test classes to wipe and reload the internal data \ No newline at end of file
private static void clear() {
init();
}
}
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
package org.jivesoftware.admin; package org.jivesoftware.admin;
import org.jivesoftware.util.StringUtils; import org.jivesoftware.util.StringUtils;
import org.dom4j.Element;
import javax.servlet.jsp.tagext.BodyTagSupport; import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspException;
...@@ -177,51 +178,51 @@ public class SidebarTag extends BodyTagSupport { ...@@ -177,51 +178,51 @@ public class SidebarTag extends BodyTagSupport {
if (subPageID != null || pageID != null) { if (subPageID != null || pageID != null) {
if (pageID == null) { if (pageID == null) {
pageID = AdminConsole.lookupPageID(subPageID); Element subPage = AdminConsole.getElemnetByID(subPageID);
pageID = subPage.getParent().getParent().attributeValue("id");
} }
// Top level menu items // Top level menu items
if (AdminConsole.getItems().size() > 0) { if (AdminConsole.getModel().elements().size() > 0) {
JspWriter out = pageContext.getOut(); JspWriter out = pageContext.getOut();
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
AdminConsole.Item current = null; Element current = null;
AdminConsole.Item subcurrent = null; Element subcurrent = null;
if (subPageID != null) { if (subPageID != null) {
subcurrent = AdminConsole.getItem(subPageID); subcurrent = AdminConsole.getElemnetByID(subPageID);
// Lookup the pageID based on the subPageID:
pageID = AdminConsole.lookupPageID(subPageID);
} }
current = AdminConsole.getElemnetByID(pageID);
AdminConsole.Item root = AdminConsole.getRootByChildID(pageID); Element currentTab = (Element)AdminConsole.getModel().selectSingleNode(
current = AdminConsole.getItem(pageID); "//*[@id='" + pageID + "']/ancestor::tab");
boolean isSubmenu = false; boolean isSubmenu = false;
if (subPageID != null && current != null) { if (subcurrent != null) {
isSubmenu = AdminConsole.isSubMenItem(subcurrent); isSubmenu = subcurrent.getParent().getParent().getName().equals("item");
} }
// Loop through all items in the root, print them out // Loop through all items in the root, print them out
if (root != null) { if (currentTab != null) {
Collection items = root.getItems(); Collection items = currentTab.elements();
if (items.size() > 0) { if (items.size() > 0) {
buf.append("<ul>"); buf.append("<ul>");
for (Iterator iter=items.iterator(); iter.hasNext(); ) { for (Iterator iter=items.iterator(); iter.hasNext(); ) {
AdminConsole.Item item = (AdminConsole.Item)iter.next(); Element sidebar = (Element)iter.next();
String header = item.getName(); String header = sidebar.attributeValue("name");
// Print the header: // Print the header:
String hcss = getHeadercss(); String hcss = getHeadercss();
if (hcss == null) { if (hcss == null) {
hcss = ""; hcss = "";
} }
buf.append("<li class=\"").append(hcss).append("\">").append(clean(header)).append("</li>"); buf.append("<li class=\"").append(hcss).append("\">").append(clean(header)).append("</li>");
// Now print all subitems: // Now print all items:
for (Iterator subitems=item.getItems().iterator(); subitems.hasNext(); ) { for (Iterator subitems=sidebar.elementIterator(); subitems.hasNext(); ) {
AdminConsole.Item subitem = (AdminConsole.Item)subitems.next(); Element item = (Element)subitems.next();
String subitemID = subitem.getId(); String subitemID = item.attributeValue("id");
String subitemName = subitem.getName(); String subitemName = item.attributeValue("name");
String subitemURL = subitem.getUrl(); String subitemURL = item.attributeValue("url");
String subitemDescr = subitem.getDescription(); String subitemDescr = item.attributeValue("description");
String value = getBodyContent().getString(); String value = getBodyContent().getString();
if (value != null) { if (value != null) {
value = StringUtils.replace(value, "[id]", clean(subitemID)); value = StringUtils.replace(value, "[id]", clean(subitemID));
...@@ -230,7 +231,7 @@ public class SidebarTag extends BodyTagSupport { ...@@ -230,7 +231,7 @@ public class SidebarTag extends BodyTagSupport {
value = StringUtils.replace(value, "[url]", clean(subitemURL)); value = StringUtils.replace(value, "[url]", clean(subitemURL));
} }
String css = getCss(); String css = getCss();
boolean isCurrent = subitem.equals(current); boolean isCurrent = item.equals(current);
boolean showSubmenu = subPageID != null; boolean showSubmenu = subPageID != null;
if (isCurrent && !showSubmenu) { if (isCurrent && !showSubmenu) {
css = getCurrentcss(); css = getCurrentcss();
...@@ -239,24 +240,24 @@ public class SidebarTag extends BodyTagSupport { ...@@ -239,24 +240,24 @@ public class SidebarTag extends BodyTagSupport {
// Print out a submenu if one exists: // Print out a submenu if one exists:
if (isSubmenu && isCurrent) { if (isSubmenu && isCurrent) {
// Get the parent of the current item so we can get its items - those will be // Get the parent of the current item so we can get its
// siblings of the current item: // items - those will be siblings of the current item:
Iterator siblings = subcurrent.getParent().getItems().iterator(); Iterator siblings = subcurrent.getParent().elementIterator();
boolean hadNext = siblings.hasNext(); boolean hadNext = siblings.hasNext();
if (hadNext) { if (hadNext) {
// Print out beginning UL // Print out beginning UL
buf.append("<ul class=\"subitems\">\n"); buf.append("<ul class=\"subitems\">\n");
// Print the header LI // Print the header LI
String subheader = subcurrent.getParent().getName(); String subheader = subcurrent.getParent().attributeValue("name");
buf.append("<li class=\"").append(hcss).append("\">").append(clean(subheader)).append("</li>"); buf.append("<li class=\"").append(hcss).append("\">").append(clean(subheader)).append("</li>");
} }
String extraParams = pageInfo.getExtraParams(); String extraParams = pageInfo.getExtraParams();
while (siblings.hasNext()) { while (siblings.hasNext()) {
AdminConsole.Item sibling = (AdminConsole.Item)siblings.next(); Element sibling = (Element)siblings.next();
String sibID = sibling.getId(); String sibID = sibling.attributeValue("id");
String sibName = sibling.getName(); String sibName = sibling.attributeValue("name");
String sibDescr = sibling.getDescription(); String sibDescr = sibling.attributeValue("description");
String sibURL = sibling.getUrl(); String sibURL = sibling.attributeValue("url");
if (extraParams != null) { if (extraParams != null) {
sibURL += ((sibURL.indexOf('?') > -1 ? "&" : "?") + extraParams); sibURL += ((sibURL.indexOf('?') > -1 ? "&" : "?") + extraParams);
} }
......
...@@ -12,13 +12,13 @@ ...@@ -12,13 +12,13 @@
package org.jivesoftware.admin; package org.jivesoftware.admin;
import org.jivesoftware.util.StringUtils; import org.jivesoftware.util.StringUtils;
import org.dom4j.Element;
import javax.servlet.jsp.tagext.BodyTagSupport; import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.JspWriter;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import java.util.Collection; import java.util.List;
import java.util.Iterator;
import java.io.IOException; import java.io.IOException;
/** /**
...@@ -123,26 +123,32 @@ public class TabsTag extends BodyTagSupport { ...@@ -123,26 +123,32 @@ public class TabsTag extends BodyTagSupport {
if (pageInfo != null) { if (pageInfo != null) {
pageID = pageInfo.getPageID(); pageID = pageInfo.getPageID();
} }
// Get root items from the data model: // Get tabs from the model:
Collection<AdminConsole.Item> items = AdminConsole.getItems(); List tabs = AdminConsole.getModel().selectNodes("//tab");
if (items.size() > 0) { if (tabs.size() > 0) {
JspWriter out = pageContext.getOut(); JspWriter out = pageContext.getOut();
// Build up the output in a buffer (is probably faster than a bunch of out.write's) // Build up the output in a buffer (is probably faster than a bunch of out.write's)
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
buf.append("<ul>"); buf.append("<ul>");
String body = getBodyContent().getString(); String body = getBodyContent().getString();
// For each root item, print out an LI // For each tab, print out an <LI>.
AdminConsole.Item root = AdminConsole.getRootByChildID(pageID); Element currentTab = null;
for (AdminConsole.Item item : items) { if (pageID != null) {
currentTab = (Element)AdminConsole.getModel().selectSingleNode(
"//*[@id='" + pageID + "']/ancestor::tab");
}
for (int i=0; i<tabs.size(); i++) {
Element tab = (Element)tabs.get(i);
String value = body; String value = body;
if (value != null) { if (value != null) {
value = StringUtils.replace(value, "[id]", clean(item.getId())); // The URL for the tab should be the URL of the first item in the tab.
value = StringUtils.replace(value, "[url]", clean(item.getUrl())); value = StringUtils.replace(value, "[id]", clean(tab.attributeValue("id")));
value = StringUtils.replace(value, "[name]", clean(item.getName())); value = StringUtils.replace(value, "[url]", clean(tab.attributeValue("url")));
value = StringUtils.replace(value, "[description]", clean(item.getDescription())); value = StringUtils.replace(value, "[name]", clean(tab.attributeValue("name")));
value = StringUtils.replace(value, "[description]", clean(tab.attributeValue("description")));
} }
String css = getCss(); String css = getCss();
if (item.equals(root)) { if (tab.equals(currentTab)) {
css = getCurrentcss(); css = getCurrentcss();
} }
buf.append("<li class=\"").append(css).append("\">"); buf.append("<li class=\"").append(css).append("\">");
...@@ -171,4 +177,4 @@ public class TabsTag extends BodyTagSupport { ...@@ -171,4 +177,4 @@ public class TabsTag extends BodyTagSupport {
private String clean(String in) { private String clean(String in) {
return (in == null ? "" : StringUtils.replace(in, "'", "\\'")); return (in == null ? "" : StringUtils.replace(in, "'", "\\'"));
} }
} }
\ No newline at end of file
...@@ -131,7 +131,7 @@ public class PluginManager { ...@@ -131,7 +131,7 @@ public class PluginManager {
Attribute attr = (Attribute)urls.get(i); Attribute attr = (Attribute)urls.get(i);
attr.setValue("/plugins/" + pluginDir.getName() + "/" + attr.getValue()); attr.setValue("/plugins/" + pluginDir.getName() + "/" + attr.getValue());
} }
AdminConsole.addXMLSource(adminElement); AdminConsole.addModel(adminElement);
} }
} }
else { else {
......
...@@ -5,9 +5,9 @@ ...@@ -5,9 +5,9 @@
<logo-image>images/header-title.gif</logo-image> <logo-image>images/header-title.gif</logo-image>
</global> </global>
<tab id="server" name="Server" description="Click to manage server settings"> <tab id="tab-server" name="Server" url="index.jsp" description="Click to manage server settings">
<sidebar name="Server Manager"> <sidebar id="sidebar-server-manager" name="Server Manager">
<item id="server-settings" name="Server Settings" <item id="server-settings" name="Server Settings"
url="index.jsp" url="index.jsp"
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
description="Click to view server logs" /> description="Click to view server logs" />
</sidebar> </sidebar>
<sidebar name="Server Settings"> <sidebar id="sidebar-server-settings" name="Server Settings">
<item id="server-reg-and-login" name="Registration &amp; Login" <item id="server-reg-and-login" name="Registration &amp; Login"
url="reg-settings.jsp" url="reg-settings.jsp"
...@@ -54,15 +54,15 @@ ...@@ -54,15 +54,15 @@
</sidebar> </sidebar>
</tab> </tab>
<tab id="users" name="Users" description="Click to manage users"> <tab id="tab-users" name="Users" url="user-summary.jsp" description="Click to manage users">
<sidebar name="Users"> <sidebar id="sidebar-users" name="Users">
<item id="user-summary" name="User Summary" <item id="user-summary" name="User Summary"
url="user-summary.jsp" url="user-summary.jsp"
description="Click to see a list of users in the system"> description="Click to see a list of users in the system">
<subsidebar name="User Options"> <sidebar id="sidebar-users-options" name="User Options">
<item id="user-properties" name="User Properties" <item id="user-properties" name="User Properties"
url="user-properties.jsp" url="user-properties.jsp"
...@@ -75,7 +75,7 @@ ...@@ -75,7 +75,7 @@
<item id="user-delete" name="Delete User" <item id="user-delete" name="Delete User"
url="user-delete.jsp" url="user-delete.jsp"
description="Click to delete the user" /> description="Click to delete the user" />
</subsidebar> </sidebar>
</item> </item>
<item id="user-create" name="Create New User" <item id="user-create" name="Create New User"
...@@ -88,9 +88,9 @@ ...@@ -88,9 +88,9 @@
</sidebar> </sidebar>
</tab> </tab>
<tab id="session" name="Sessions" description="Click to manage connected sessions"> <tab id="tab-session" name="Sessions" url="session-summary.jsp" description="Click to manage connected sessions">
<sidebar name="Sessions"> <sidebar id="sidebar-session" name="Sessions">
<item id="session-summary" name="View Current Sessions" <item id="session-summary" name="View Current Sessions"
url="session-summary.jsp" url="session-summary.jsp"
...@@ -102,9 +102,9 @@ ...@@ -102,9 +102,9 @@
</sidebar> </sidebar>
</tab> </tab>
<tab id="groupchat" name="Group Chat" description="Click to manage group chat settings"> <tab id="tab-groupchat" name="Group Chat" url="muc-server-props-edit-form.jsp" description="Click to manage group chat settings">
<sidebar name="Group Chat Settings"> <sidebar id="sidebar-groupchat-settings" name="Group Chat Settings">
<item id="muc-server-props" name="Service Properties" <item id="muc-server-props" name="Service Properties"
url="muc-server-props-edit-form.jsp" url="muc-server-props-edit-form.jsp"
......
...@@ -15,6 +15,7 @@ import java.util.Iterator; ...@@ -15,6 +15,7 @@ import java.util.Iterator;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.jivesoftware.admin.AdminConsole; import org.jivesoftware.admin.AdminConsole;
import org.dom4j.Element;
public class AdminConsoleTest extends TestCase { public class AdminConsoleTest extends TestCase {
...@@ -27,9 +28,9 @@ public class AdminConsoleTest extends TestCase { ...@@ -27,9 +28,9 @@ public class AdminConsoleTest extends TestCase {
*/ */
public void tearDown() throws Exception { public void tearDown() throws Exception {
Class c = AdminConsole.class; Class c = AdminConsole.class;
Method clear = c.getDeclaredMethod("clear", (Class[])null); Method init = c.getDeclaredMethod("init", (Class[])null);
clear.setAccessible(true); init.setAccessible(true);
clear.invoke((Object)null, (Object[])null); init.invoke((Object)null, (Object[])null);
} }
public void testGetGlobalProps() throws Exception { public void testGetGlobalProps() throws Exception {
...@@ -44,7 +45,7 @@ public class AdminConsoleTest extends TestCase { ...@@ -44,7 +45,7 @@ public class AdminConsoleTest extends TestCase {
String filename = TestUtils.prepareFilename( String filename = TestUtils.prepareFilename(
"./resources/org/jivesoftware/admin/AdminConsoleTest.admin-sidebar-01.xml"); "./resources/org/jivesoftware/admin/AdminConsoleTest.admin-sidebar-01.xml");
InputStream in = new FileInputStream(filename); InputStream in = new FileInputStream(filename);
AdminConsole.addXMLSource(in); AdminConsole.addModel(in);
in.close(); in.close();
String name = AdminConsole.getAppName(); String name = AdminConsole.getAppName();
assertEquals("Foo Bar", name); assertEquals("Foo Bar", name);
...@@ -57,18 +58,18 @@ public class AdminConsoleTest extends TestCase { ...@@ -57,18 +58,18 @@ public class AdminConsoleTest extends TestCase {
String filename = TestUtils.prepareFilename( String filename = TestUtils.prepareFilename(
"./resources/org/jivesoftware/admin/AdminConsoleTest.admin-sidebar-02.xml"); "./resources/org/jivesoftware/admin/AdminConsoleTest.admin-sidebar-02.xml");
InputStream in = new FileInputStream(filename); InputStream in = new FileInputStream(filename);
AdminConsole.addXMLSource(in); AdminConsole.addModel(in);
in.close(); in.close();
Collection items = AdminConsole.getItems(); Collection tabs = AdminConsole.getModel().selectNodes("//tab");
assertNotNull(items); assertNotNull(tabs);
assertTrue(items.size() > 0); assertTrue(tabs.size() > 0);
boolean found = false; boolean found = false;
for (Iterator iter=items.iterator(); iter.hasNext(); ) { for (Iterator iter=tabs.iterator(); iter.hasNext(); ) {
AdminConsole.Item item = (AdminConsole.Item)iter.next(); Element tab = (Element)iter.next();
if ("foobar".equals(item.getId())) { if ("foobar".equals(tab.attributeValue("id"))) {
found = true; found = true;
assertEquals("Foo Bar", item.getName()); assertEquals("Foo Bar", tab.attributeValue("name"));
assertEquals("Click to see foo bar", item.getDescription()); assertEquals("Click to see foo bar", tab.attributeValue("description"));
} }
} }
if (!found) { if (!found) {
...@@ -81,16 +82,15 @@ public class AdminConsoleTest extends TestCase { ...@@ -81,16 +82,15 @@ public class AdminConsoleTest extends TestCase {
String filename = TestUtils.prepareFilename( String filename = TestUtils.prepareFilename(
"./resources/org/jivesoftware/admin/AdminConsoleTest.admin-sidebar-03.xml"); "./resources/org/jivesoftware/admin/AdminConsoleTest.admin-sidebar-03.xml");
InputStream in = new FileInputStream(filename); InputStream in = new FileInputStream(filename);
AdminConsole.addXMLSource(in); AdminConsole.addModel(in);
in.close(); in.close();
Collection items = AdminConsole.getItems();
boolean found = false; boolean found = false;
for (Iterator iter=items.iterator(); iter.hasNext(); ) { for (Iterator tabs=AdminConsole.getModel().selectNodes("//tab").iterator(); tabs.hasNext(); ) {
AdminConsole.Item item = (AdminConsole.Item)iter.next(); Element tab = (Element)tabs.next();
if ("server".equals(item.getId())) { if ("server".equals(tab.attributeValue("id"))) {
found = true; found = true;
assertEquals("New Server Title", item.getName()); assertEquals("New Server Title", tab.attributeValue("name"));
assertEquals("Testing 1 2 3", item.getDescription()); assertEquals("Testing 1 2 3", tab.attributeValue("description"));
} }
} }
if (!found) { if (!found) {
......
<?xml version="1.0"?> <?xml version="1.0"?>
<adminconsole> <adminconsole>
<tab id="foobar" name="Foo Bar" description="Click to see foo bar" /> <tab id="foobar" name="Foo Bar" url="foobar.jsp" description="Click to see foo bar" />
</adminconsole> </adminconsole>
\ No newline at end of file
...@@ -3,5 +3,5 @@ ...@@ -3,5 +3,5 @@
<!-- Insert a tab with the same ID to overwrite the tab --> <!-- Insert a tab with the same ID to overwrite the tab -->
<adminconsole> <adminconsole>
<tab id="server" name="New Server Title" description="Testing 1 2 3" /> <tab id="server" name="New Server Title" url="newurl.jsp" description="Testing 1 2 3" />
</adminconsole> </adminconsole>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment