/*
* Copyright(c) 2005 Center for E-Commerce Infrastructure Development, The
* University of Hong Kong (HKU). All Rights Reserved.
*
* This software is licensed under the Apache License Version 2.0 [1]
*
* [1] http://www.apache.org/licenses/LICENSE-2.0.txt
*/
package hk.hku.cecid.piazza.corvus.admin.listener;
import hk.hku.cecid.piazza.commons.Sys;
import hk.hku.cecid.piazza.commons.pagelet.PageletStore;
import hk.hku.cecid.piazza.commons.pagelet.TemplateElement;
import hk.hku.cecid.piazza.commons.pagelet.xslt.BorderLayoutPageletAdaptor;
import hk.hku.cecid.piazza.commons.util.DataFormatter;
import hk.hku.cecid.piazza.commons.util.PropertyTree;
import hk.hku.cecid.piazza.corvus.admin.menu.MenuComponent;
import hk.hku.cecid.piazza.corvus.core.Kernel;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import javax.servlet.http.HttpServletRequest;
import javax.xml.transform.Source;
/**
* AdminPageletAdaptor is an HTTP-XSLT pagelet adaptor. It generally serves as a
* main framework for the admin pages. Pages generated by this pagelet are in
* border layout format corresponding to the pre-defined template.
* <p>
* Subclasses are expected to override the getCenterSource() method and provide
* implementation for the generation of the transformation source which
* contributes to the center region of the page being rendered.
*
* @author Hugo Y. K. Lam
*
*/
public class AdminPageletAdaptor extends BorderLayoutPageletAdaptor {
/**
* The pagelet store of this pagelet.
*/
public final static PageletStore store = new PageletStore();
/**
* The modules of this pagelet.
*/
public final static Set modules = Collections.synchronizedSortedSet(new TreeSet());
/**
* The prefix of the attriute name used in this pagelet.
*/
protected final static String ATTR_PREFIX = AdminPageletAdaptor.class.getName() + ".";
/**
* The attribute name of the message attribute.
*/
protected final static String ATTR_MESSAGE = ATTR_PREFIX + "message";
/**
* Indicator of menu type Module.
*/
private final static String MENU_TYPE_MODULE = "module";
/**
* Indicator of menu type Tab.
*/
private final static String MENU_TYPE_TAB = "tab";
/**
* @see hk.hku.cecid.piazza.commons.pagelet.PageletStore
*/
protected PageletStore getPageletStore() {
return store;
}
/**
* Gets the module ID that this pagelet represents. This method will look
* up the listener parameter 'module'.
*
* @param request the servlet request.
* @return the module ID.
*/
protected String getModuleId(HttpServletRequest request) {
return getParameters().getProperty("module");
}
/**
* Gets the tab ID that this pagelet represents. This method will look
* up the listener parameter 'tab'.
*
* @param request the servlet request.
* @return the tab ID.
*/
protected String getTabId(HttpServletRequest request) {
return getParameters().getProperty("tab");
}
/**
* Gets the transformation source of the menu tabs.
*
* @see hk.hku.cecid.piazza.commons.pagelet.xslt.BorderLayoutPageletAdaptor#getNorthSource(javax.servlet.http.HttpServletRequest)
*/
protected Source getNorthSource(HttpServletRequest request) {
return getMenuComponentSource(request, MENU_TYPE_TAB);
}
/**
* Gets the transformation source of the menu modules.
*
* @see hk.hku.cecid.piazza.commons.pagelet.xslt.BorderLayoutPageletAdaptor#getWestSource(javax.servlet.http.HttpServletRequest)
*/
protected Source getWestSource(HttpServletRequest request) {
return getMenuComponentSource(request, MENU_TYPE_MODULE);
}
/**
* Gets the transformation source of the specified menu type.
*
* @param request the servlet request.
* @param type the menu type.
* @return the transformation source of the specified menu type.
*/
private Source getMenuComponentSource(HttpServletRequest request, String type) {
Source componentSource = (Source)request.getAttribute(ATTR_PREFIX + type);
if (componentSource == null) {
Collection tabs = generateMenuComponentSource(request, modules, getModuleId(request), -1, MENU_TYPE_MODULE);
generateMenuComponentSource(request, tabs, getTabId(request), 12, MENU_TYPE_TAB);
componentSource = (Source)request.getAttribute(ATTR_PREFIX + type);
}
return componentSource;
}
/**
* Generates the transformation source of the specified menu type by the
* given menu components. The generated source will be stored as a request
* attribute having an attribute name [ATTR_PREFIX][MENU_TYPE].
*
* @param request the servlet request.
* @param components the menu components.
* @param selectedId the ID of the selected component.
* @param maxComponentWidth the maximum width of each component's caption.
* @param type the menu type.
* @return the sub-menu components of the selected menu or an empty collection.
*
* @see #ATTR_PREFIX
*/
private Collection generateMenuComponentSource(HttpServletRequest request, Collection components, String selectedId, int maxComponentWidth, String type) {
boolean isAlreadySelected = false;
String basePath = "/"+type+"s";
PropertyTree dom = new PropertyTree();
dom.setProperty(basePath, "");
List subcomponents = null;
Iterator allComponents = components.iterator();
for (int i=1; allComponents.hasNext(); i++) {
MenuComponent component = (MenuComponent)allComponents.next();
boolean componentSelected = !isAlreadySelected &&
selectedId != null &&
selectedId.equals(component.getId());
isAlreadySelected = isAlreadySelected || componentSelected;
if (component.isVisible()) {
String componentName = component.getName();
if (maxComponentWidth >= 3) {
if (componentName.length()>maxComponentWidth) {
componentName = componentName.substring(0,
maxComponentWidth-3) + "...";
}
}
String componentPath = basePath + "/"+ type;
dom.setProperty(componentPath+"["+i+"]/name", componentName);
dom.setProperty(componentPath+"["+i+"]/description", component.getDescription());
dom.setProperty(componentPath+"["+i+"]/link", request.getContextPath() + component.getLink());
if (componentSelected) {
dom.setProperty(componentPath+"["+i+"]/selected", "");
}
}
else {
i--;
}
if (componentSelected) {
subcomponents = component.getChildren();
}
}
request.setAttribute(ATTR_PREFIX + type, dom.getSource());
return (subcomponents == null? Collections.EMPTY_LIST:subcomponents);
}
/**
* Gets the transformation source of the message area. The source will be
* generated according to the message attribute.
*
* @param request the servlet request.
* @return the transformation source of the message area.
*
* @see #ATTR_MESSAGE
* @see hk.hku.cecid.piazza.commons.pagelet.xslt.BorderLayoutPageletAdaptor#getSouthSource(javax.servlet.http.HttpServletRequest)
*/
protected Source getSouthSource(HttpServletRequest request) {
Object message = request.getAttribute(ATTR_MESSAGE);
PropertyTree dom = new PropertyTree();
dom.setProperty("/message", "");
if (message!=null) {
dom.setProperty("description", message.toString());
}
return dom.getSource();
}
/**
* Gets the transformation source of the main body. This method by default
* generates a transformation source of the system status. Sub-classes
* should override this method and provide its own implementation.
*
* @param request the servlet request.
* @return the transformation source of the system status.
* @see hk.hku.cecid.piazza.commons.pagelet.xslt.BorderLayoutPageletAdaptor#getCenterSource(javax.servlet.http.HttpServletRequest)
*/
protected Source getCenterSource(HttpServletRequest request) {
String action = request.getParameter(REQ_PARAM_ACTION);
if ("gc".equalsIgnoreCase(action)) {
System.gc();
request.setAttribute(ATTR_MESSAGE, "Garbage collection initiated");
}
else if ("final".equalsIgnoreCase(action)) {
System.runFinalization();
request.setAttribute(ATTR_MESSAGE, "Finalization initiated");
}
PropertyTree dom = new PropertyTree();
dom.setProperty("/home", "");
Date startupTime = Kernel.getInstance().getStartupTime();
Date currentTime = new Date(System.currentTimeMillis());
long elapsedTime = currentTime.getTime() - startupTime.getTime();
long days = elapsedTime/86400000;
long hours= (elapsedTime%86400000)/3600000;
long mins = ((elapsedTime%86400000)%3600000)/60000;
long secs = (((elapsedTime%86400000)%3600000)%60000)/1000;
String upTime = days + " days " + hours + " hours " + mins + " mins " + secs + " secs";
dom.setProperty("system/name", Sys.main.getName());
dom.setProperty("system/version", Sys.main.getVersion());
dom.setProperty("system/buildID", Sys.main.getBuildID());
dom.setProperty("system/startup-time", startupTime.toString());
dom.setProperty("system/current-time", currentTime.toString());
dom.setProperty("system/up-time", upTime);
dom.setProperty("system/processors", String.valueOf(Runtime.getRuntime().availableProcessors()));
long maxMemory = Runtime.getRuntime().maxMemory()/1048576;
long totalMemory = Runtime.getRuntime().totalMemory()/1048576;
long freeMemory = Runtime.getRuntime().freeMemory()/1048576;
long usedMemory = totalMemory - freeMemory;
String memoryUsage = DataFormatter.getInstance().formatDecimal(
(((double)usedMemory) / maxMemory) * 100);
dom.setProperty("memory/max", maxMemory + " MB");
dom.setProperty("memory/total", totalMemory + " MB");
dom.setProperty("memory/used", usedMemory + " MB");
dom.setProperty("memory/free", freeMemory + " MB");
dom.setProperty("memory/usage", memoryUsage + "%");
return dom.getSource();
}
/**
* Gets transformation source which represents the error generated by any of
* the pagelets composing the page being generated by this pagelet.
*
* @see hk.hku.cecid.piazza.commons.pagelet.xslt.HttpXsltPageletAdaptor#getErrorSource(TemplateElement,Throwable,HttpServletRequest)
*/
protected Source getErrorSource(TemplateElement element, Throwable e, HttpServletRequest request) {
PropertyTree dom = new PropertyTree();
dom.setProperty("/error", "");
dom.setProperty("plugin", getModuleId(request));
dom.setProperty("home_directory", Sys.main.properties.getProperty("/corvus/home"));
dom.setProperty("time", new Date().toString());
return dom.getSource();
}
}