package diskCacheV111.poolManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.OutputStream; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.TreeMap; import diskCacheV111.util.CacheException; import diskCacheV111.util.HTMLWriter; import diskCacheV111.util.PnfsId; import diskCacheV111.util.TimeoutCacheException; import diskCacheV111.vehicles.PnfsMapPathMessage; import diskCacheV111.vehicles.RestoreHandlerInfo; import diskCacheV111.vehicles.StorageInfo; import diskCacheV111.vehicles.hsmControl.HsmControlGetBfDetailsMsg; import dmg.cells.nucleus.CellCommandListener; import dmg.cells.nucleus.CellEndpoint; import dmg.cells.nucleus.CellInfo; import dmg.cells.nucleus.CellInfoProvider; import dmg.cells.nucleus.CellMessageSender; import dmg.cells.nucleus.CellPath; import dmg.cells.nucleus.DomainContextAware; import dmg.cells.nucleus.NoRouteToCellException; import dmg.util.AgingHash; import dmg.util.HttpException; import dmg.util.HttpRequest; import dmg.util.HttpResponseEngine; import org.dcache.cells.CellStub; import org.dcache.namespace.FileAttribute; import org.dcache.poolmanager.Partition; import org.dcache.util.Args; import org.dcache.vehicles.FileAttributes; import org.dcache.vehicles.PnfsGetFileAttributes; import static java.util.concurrent.TimeUnit.SECONDS; public class HttpPoolMgrEngineV3 implements HttpResponseEngine, Runnable, CellInfoProvider, CellMessageSender, DomainContextAware, CellCommandListener { private static final String PARAMETER_DCACHE = "dcache"; private static final String PARAMETER_GREP = "grep"; private static final String PARAMETER_LINKGROUP = "linkGroup"; private static final String PARAMETER_NET = "net"; private static final String PARAMETER_PROTOCOL = "protocol"; private static final String PARAMETER_SORT = "sort"; private static final String PARAMETER_STORE = "store"; private static final String PARAMETER_TYPE = "type"; private static final Logger _log = LoggerFactory.getLogger(HttpPoolMgrEngineV3.class); private static final long TIMEOUT = 20000; private final Thread _restoreCollector; private CellStub _poolManager; private CellStub _pnfsManager; private CellStub _hsmController; private final AgingHash _pnfsPathMap = new AgingHash(500); private final AgingHash _fileAttributesMap = new AgingHash(500); private final boolean _takeAll = true; private static final ThreadLocal<SimpleDateFormat> _formatter = new ThreadLocal<SimpleDateFormat>() { @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("MM.dd HH:mm:ss"); } }; private volatile List<Object[]> _lazyRestoreList = new ArrayList<>(); private long _collectorUpdate = 60000L; private long _errorCounter; private long _requestCounter; private final Object _updateLock = new Object(); private boolean _addStorageInfo; private boolean _addHsmInfo; private String[] _siDetails; private String _cssFile = "/poolInfo/css/default.css"; private Map<String, Object> _context; public HttpPoolMgrEngineV3(String[] argsString) { for (int i = 0; i < argsString.length; i++) { _log.info("HttpPoolMgrEngineV3 : argument : "+i+" : "+argsString[i]); if (argsString[i].equals("addStorageInfo")) { _addStorageInfo = true; _log.info("Option accepted : addStorageInfo"); } else if (argsString[i].equals("addHsmInfo")) { _addHsmInfo = true; _log.info("Option accepted : addHsmInfo"); } else if (argsString[i].startsWith("details=")) { _log.info("Details for lazy restore : "+argsString[i]); decodeDetails(argsString[i]); } else if (argsString[i].startsWith("css=")) { decodeCss(argsString[i].substring(4)); } } _restoreCollector = new Thread(this, "restore-collector"); _log.info("Using CSS file : "+_cssFile); } @Override public void setCellEndpoint(CellEndpoint endpoint) { // FIXME: Do not hardcode cell addresses _poolManager = new CellStub(endpoint, new CellPath("PoolManager"), TIMEOUT, SECONDS); _pnfsManager = new CellStub(endpoint, new CellPath("PnfsManager"), TIMEOUT, SECONDS); _hsmController = new CellStub(endpoint, new CellPath("HsmManager"), TIMEOUT, SECONDS); } @Override public void setDomainContext(Map<String, Object> context) { _context = context; } @Override public void startup() { _restoreCollector.start(); } @Override public void shutdown() { _restoreCollector.interrupt(); try { _restoreCollector.join(); } catch (InterruptedException e) { _log.warn("Interrupted while waiting for restore-collector to terminate"); } } private void decodeCss(String cssDetails) { cssDetails = cssDetails.trim(); if ((!cssDetails.isEmpty()) && !cssDetails.equals("default")) { _cssFile = cssDetails; } } private void decodeDetails(String details) { if (details.startsWith("details=") && (details.length() >= 9)) { _siDetails = details.substring(8).split(","); } } @Override public void run() { _log.info("Restore Collector Thread started"); try { while (!Thread.interrupted()) { try { synchronized (_updateLock) { _updateLock.wait(_collectorUpdate); } runRestoreCollector(); } catch(NoRouteToCellException e) { _log.warn("Restore Collector got : " + e, e); } } } catch (InterruptedException e) { _log.debug("Restore Collector interrupted"); } } @Override public void getInfo(PrintWriter pw) { pw.println(" PoolManagerEngine : [$Id: HttpPoolMgrEngineV3.java,v 1.26 2007-08-16 20:20:56 behrmann Exp $]"); pw.println(" Request Counter : "+_requestCounter); pw.println(" Error Counter : "+_errorCounter); pw.println(" Collector Update : "+(_collectorUpdate/1000L)+" seconds"); pw.println(" addStorageInfo : "+_addStorageInfo); pw.println(" addHsmInfo : "+_addHsmInfo); } public static final String hh_set_update = "[<updateTime/sec>]"; public String ac_set_update_$_0_1(Args args) { if (args.argc() == 0) { synchronized (_updateLock) { _updateLock.notifyAll(); } } else { long x = Long.parseLong(args.argv(0)); if (x < 30) { throw new IllegalArgumentException("<updateTime> must be > 30"); } synchronized (_updateLock) { _collectorUpdate = x * 1000; _updateLock.notifyAll(); } } return ""; } private void runRestoreCollector() throws NoRouteToCellException, InterruptedException { RestoreHandlerInfo[] infos; try { infos = _poolManager.sendAndWait("xrc ls", RestoreHandlerInfo[].class); } catch (CacheException | NoRouteToCellException e) { _log.warn("runRestoreCollector : failure reply from PoolManager : " + e.getMessage()); return; } List<Object[]> agedList = new ArrayList<>(); long cut = System.currentTimeMillis() - (1000L * 60L * 2L); for (RestoreHandlerInfo info : infos) { if (_takeAll || (info.getStartTime() < cut)) { try { Object[] a = new Object[3]; a[0] = info; String name = info.getName(); String pnfsId = name.substring(0,name.indexOf('@')); // // collect the pathes // String path = (String)_pnfsPathMap.get(pnfsId); if (path == null) { path = getPathByPnfsId(pnfsId); } if (path == null) { a[1] = pnfsId; } else { _pnfsPathMap.put(pnfsId, a[1] = path); } // // collect the storage infos // if (_addStorageInfo) { FileAttributes fileAttributes = (FileAttributes) _fileAttributesMap.get(pnfsId); if (fileAttributes == null) { fileAttributes = getFileAttributesByPnfsId(pnfsId); } if (fileAttributes != null) { StorageInfo storageInfo = fileAttributes.getStorageInfo(); if (_addHsmInfo) { StorageInfo si = getHsmInfoByStorageInfo(pnfsId,storageInfo); if (si != null) { storageInfo = si; fileAttributes.setStorageInfo(si); } } if (_siDetails != null) { // allows to select items if (fileAttributes.isDefined(FileAttribute.SIZE)) { storageInfo.setKey("size", String.valueOf(fileAttributes.getSize())); } storageInfo.setKey("new", String.valueOf(storageInfo.isCreatedOnly())); storageInfo.setKey("stored", String.valueOf(storageInfo.isStored())); storageInfo.setKey("sClass",fileAttributes.getStorageClass()); storageInfo.setKey("cClass",fileAttributes.getCacheClass()); storageInfo.setKey("hsm",fileAttributes.getHsm()); } _fileAttributesMap.put(pnfsId, a[2] = storageInfo); } } agedList.add(a); } catch (Exception e) { _log.warn(e.toString(), e); } } } _lazyRestoreList = agedList; } private StorageInfo getHsmInfoByStorageInfo(String pnfsId, StorageInfo storageInfo) { try { HsmControlGetBfDetailsMsg msg = new HsmControlGetBfDetailsMsg(new PnfsId(pnfsId),storageInfo,"default"); return _hsmController.sendAndWait(msg).getStorageInfo(); } catch (InterruptedException | CacheException | NoRouteToCellException e) { _log.warn(e.toString(), e); return null; } } private String getPathByPnfsId(String pnfsId) { try { PnfsMapPathMessage msg = new PnfsMapPathMessage(new PnfsId(pnfsId)); return _pnfsManager.sendAndWait(msg).getGlobalPath(); } catch (InterruptedException | CacheException | NoRouteToCellException e) { _log.warn(e.toString()); return null; } } private FileAttributes getFileAttributesByPnfsId(String pnfsId) { try { PnfsGetFileAttributes msg = new PnfsGetFileAttributes(new PnfsId(pnfsId), EnumSet.of(FileAttribute.SIZE, FileAttribute.STORAGEINFO)); return _pnfsManager.sendAndWait(msg).getFileAttributes(); } catch (InterruptedException | CacheException | NoRouteToCellException e) { _log.warn(e.toString()); return null; } } private void printMenu(PrintWriter pw, String sort, String grep) { String action = "detail"; String tableDataColor = "#eeeeee"; String tableColor = "#dddddd"; String[] sel = { "PnfsId" , "i.name", "Time" , "i.start", "Pool" , "i.pool", "Status" , "i.status", "Tape" , "hsm.osm.volumeName", "StorageClass", "sclass", "Path" , "path" }; pw.println("<form name=\"input\" action=\""+action+"\" method=\"get\">"); pw.println("<center><table border=0 cellspacing=2 width=\"95%\" bgcolor=\""+tableColor+"\">"); pw.println(" <tr>"); pw.println(" <td align=center bgcolor=\""+tableDataColor+"\">"); pw.println(" <input type=\"submit\" value=\"Select\" name=\"otto\">"); pw.println(" </td>"); pw.println(" <td align=center bgcolor=\""+tableDataColor+"\">"); pw.println(" Sort by"); pw.println(" </td>"); String radio = "type=\"radio\" name=\"sort\""; String checked = "checked=\"checked\" "; for (int i = 0, n = sel.length ; i < n; i+=2) { pw.println(" <td align=center bgcolor=\""+tableDataColor+"\">"); pw.println(" <input "+radio+" id=\""+sel[i]+"\" value=\""+ sel[i+1]+"\" "+ ((((sort==null)&&(i==0))|| ((sort!=null)&&sel[i+1].equals(sort))) ? checked : "")+"/>"); pw.println(" <label for=\""+sel[i]+"\">"+sel[i]+"</label>"); pw.println(" </td>"); } pw.println(" <td align=center bgcolor=\""+tableDataColor+"\">"); pw.println(" Search <input type=\"text\" value=\""+ (grep == null ? "" : grep) +"\" name=\"grep\">"); pw.println(" </td>"); pw.println(" </tr>"); pw.println("</table></center>"); } private void printCssFile(PrintWriter pw, String filename) { if (filename.equals("test.html")) { // // table test for css (internal and external) // pw.println("<html>"); pw.println("<head>"); pw.println("<title>Titel der Datei</title>"); pw.println("<link rel=\"stylesheet\" type=\"text/css\" href=\""+_cssFile+"\">"); pw.println("</head>"); pw.println("<body>"); pw.println("<h1>This is a header - 1 </h1>"); pw.println("<h2>This is a header - 2 </h2>"); pw.println("<center>"); pw.println("<table class=\"s-table\">"); pw.println("<tr class=\"s-table\"><th class=\"s-table\">Header 1</th><th class=\"s-table\">Header 2</th></tr>"); pw.println("<tr class=\"s-table-a\"><td class=\"s-table\">entry-1</td><td class=\"s-table\">entry-2</td></tr>"); pw.println("<tr class=\"s-table-b\"><td class=\"s-table\">entry-3</td><td class=\"s-table\">entry-4</td></tr>"); pw.println("</table>"); pw.println("</body>"); pw.println("</html>"); } else if (filename.equals("default.css")) { printInternalCssFile(pw); } } private void printInternalCssFile(PrintWriter pw) { pw.println("body { background-color:orange; }"); pw.println("table.s-table { width:90%; border:1px; border-style:solid; border-spacing:0px; border-collapse:collapse; }"); pw.println("tr.s-table { background-color:#115259; color:white; font-size:18; }"); pw.println("tr.s-table-a { background-color:#bebebe; text-align:center; font-size:16; }"); pw.println("tr.s-table-b { background-color:#efefef; text-align:center; font-size:16; }"); pw.println("tr.s-table-e { background-color:red; text-align:center; font-size:16; }"); pw.println("td.s-table { border:1px ; border-style:solid; border-spacing:1px; padding:3; }"); pw.println("th.s-table { border:1px ; border-style:solid; border-spacing:1px;}"); pw.println("td.s-table-disabled { border:1px ; border-style:solid; border-spacing:0px; padding:3;}"); pw.println("td.s-table-e { background-color:red;}"); pw.println("td.s-table-regular { border:1px ; border-style:solid; border-spacing:0px; padding:3;}"); pw.println("span.s-table-disabled { color:gray ; }"); pw.println("span.s-table-regular { color:black ; }"); pw.println("a.s-table:visited { text-decoration:none; color:blue; }"); pw.println("a.s-table:link { text-decoration:none; color:blue; }"); pw.println("table.m-table { width:90%; border:0px; border-style:none; border-spacing:0px; border-collapse:collapse; }"); pw.println("td.m-table { background-color:white; text-align:center; border:1px ; border-style:solid; border-spacing:1px;}"); pw.println("a.m-table:visited { text-decoration:none; }"); pw.println("a.m-table-active:visited { text-decoration:none; color:red; }"); pw.println("a.m-table:link { text-decoration:none; }"); pw.println("a.m-table-active:link { text-decoration:none; color:red; }"); pw.println("table.l-table { width:90%; color:black; table-layout:auto;"); pw.println(" border:1px; border-style:none; border-spacing:0px; border-collapse:collapse; }"); pw.println("tr.l-table { background-color:green; }"); pw.println("td.l-table { background-color:white; color:black;"); pw.println("width:10.5%;"); pw.println("padding:4; text-align:center;"); pw.println("border:1px; border-style:solid; border-spacing:0px; border-collapse:collapse; }"); pw.println("span.l-table { font-size:16;}"); pw.println("a.l-table:visited { text-decoration:none; color:blue; }"); pw.println("a.l-table:link { text-decoration:none; color:blue; }"); pw.println("table.f-table-a { width:90%; color:black; table-layout:auto; background-color:white;"); pw.println("border:1px; border-style:solid; border-spacing:0px; border-collapse:collapse;}"); pw.println("td.f-table-a { text-align:center; padding:10; }"); pw.println("span.f-table-a { text-align:center; font-size:20px }"); pw.println("table.f-table-b { width:100%; color:black; table-layout:auto; "); pw.println(" border:1px; border-style:none; border-spacing:0px; border-collapse:collapse; }"); pw.println("th.f-table-b { width:20%;}"); pw.println("td.f-table-b { width:20%; background-color:#eeeeee; color:black;"); pw.println("padding:4; text-align:center; border:1px; border-style:solid; border-spacing:0px; }"); pw.println("span.m-title { font-size:18; color=red; }"); pw.println("a.big-link:visited { text-decoration:none; color:blue; }"); pw.println("a.big-link:link { text-decoration:none; color:blue; }"); pw.println("span.big-link { font-size:24; text-align:center }"); } @Override public void queryUrl(HttpRequest request) throws HttpException { OutputStream out = request.getOutputStream(); PrintWriter pw = request.getPrintWriter(); String[] urlItems = request.getRequestTokens(); request.printHttpHeader(0); _requestCounter ++; try { if (urlItems.length < 1) { return; } if ((urlItems.length > 1) && (urlItems[1].equals("css"))) { // // the internal css stuff (if nothing else is specifed) // if (urlItems.length > 2) { printCssFile(pw, urlItems[2]); } // } else if ((urlItems.length > 1) && (urlItems[1].equals("parameterHandler"))) { // // the parameter handler (dCache partitioning) // if (urlItems.length > 2) { // // the paramter set // if (urlItems[2].equals("set")) { printParameter(pw, urlItems.length > 3 ? urlItems[3] : "*"); } } } else if ((urlItems.length > 1) && (urlItems[1].equals("restoreHandler"))) { if (urlItems.length > 2) { if (urlItems[2].equals("lazy")) { // // LAZY retore queue // if ((urlItems.length > 3) && urlItems[3].startsWith("detail")) { String sort = request.getParameter(PARAMETER_SORT); String grep = request.getParameter(PARAMETER_GREP); printMenu(pw, sort, grep); printLazyRestoreInfo(out, sort, grep); } else { // // regular restore queue // printLazyRestoreInfo(out, null,null); } } else if (urlItems[2].startsWith("detail")) { String sort = request.getParameter(PARAMETER_SORT); String grep = request.getParameter(PARAMETER_GREP); printMenu(pw, sort, grep); printRestoreInfo(out, sort, grep); } else { printRestoreInfo(out, null, null); } } else { printRestoreInfo(out, null, null); } } else { printConfigurationPages(pw, urlItems, request); } } catch (HttpException httpe) { _errorCounter ++; throw httpe; } catch (Exception e) { _errorCounter ++; showProblem(pw, e.getMessage()); pw.println("<ul>"); for (int i = 0; i < urlItems.length; i++) { pw.println("<li> ["+i+"] "); pw.println(urlItems[i]); } pw.println("</ul>"); } finally { pw.println("</body>"); pw.println("</html>"); } } private void printConfigurationHeader(PrintWriter pw) { pw.println("<html>"); pw.println("<head>"); pw.println("<title>PoolManager (Pool SelectionUnit) Configuration</title>"); pw.println("<link rel=\"stylesheet\" type=\"text/css\" href=\""+_cssFile+"\">"); pw.println("</head>"); pw.println("<body class=\"m-body\">"); } private void printConfigurationPages(PrintWriter pw, String[] urlItems, HttpRequest request) throws HttpException, NoRouteToCellException, InterruptedException { printConfigurationHeader(pw); printPoolManagerHeader(pw, null); if (urlItems.length < 2) { showDirectory(pw); } else if (urlItems[1].equals("pools")) { showDirectory(pw, 1); queryPool(pw, urlItems[2]); } else if (urlItems[1].equals("units")) { showDirectory(pw, 3); StringBuilder sb = new StringBuilder(); int i; for (i = 2; i < (urlItems.length-1); i++) { sb.append(urlItems[i]).append("/"); } sb.append(urlItems[i]); queryUnit(pw, sb.toString()); } else if (urlItems[1].equals("ugroups")) { showDirectory(pw, 4); queryUnitGroup(pw, urlItems[2]); } else if (urlItems[1].equals("pgroups")) { showDirectory(pw, 2); queryPoolGroup(pw, urlItems[2]); } else if (urlItems[1].equals("links")) { showDirectory(pw, 5); queryLink(pw, urlItems[2]); } else if (urlItems[1].equals("linklist")) { showDirectory(pw, 7); queryLinkList(pw); } else if (urlItems[1].equals("match")) { showDirectory(pw, 6); showMatch(pw, request); } else { throw new HttpException(404, "Unknown key : "+urlItems[1]); } } private void printParameter(PrintWriter pw, String key) { try { printConfigurationHeader(pw); printPoolManagerHeader(pw, "Partition Manager"); showDirectory(pw, 0); Map<String,Partition> parameterMap = _poolManager.sendAndWait("pmx get map", Map.class); if (key.equals("section")) { printParameterInSections(pw, parameterMap); } else if (key.equals("matrix")) { printParameterInMatrix(pw, parameterMap); } } catch (TimeoutCacheException e) { showTimeout(pw); } catch (CacheException | InterruptedException | NoRouteToCellException e) { showProblem(pw, e.getMessage()); } pw.println("<hr><address>Created "+(new Date())+" $Id: HttpPoolMgrEngineV3.java,v 1.26 2007-08-16 20:20:56 behrmann Exp $"); pw.println("</body></html>"); } private void printParameterInMatrix(PrintWriter pw, Map<String,Partition> parameterMap) { Partition defaultParas = parameterMap.get("default"); if (defaultParas == null) { return; } Map<String,Object[]>[] restMap = new Map[parameterMap.size()-1]; String[] header = new String[parameterMap.size()-1]; int row = 0; for (Map.Entry<String,Partition> entry : parameterMap.entrySet()) { String mapName = entry.getKey(); if (mapName.equals("default")) { continue; } header[row] = mapName; restMap[row] = entry.getValue().toMap(); row ++; } pw.println("<center><table class=\"s-table\""); pw.print("<tr class=\"s-table\">"); pw.print("<th class=\"s-table\">Key</th><th class=\"s-table\">Default</th>"); for (int m = 0; m < restMap.length; m++) { pw.println("<th class=\"s-table\">" + header[m] + "</th>"); } pw.println("</tr>"); Map<String, Object[]> defaultMap = new TreeMap<>(defaultParas.toMap()); row = 0; String[] setColor = { "s-table-disabled", "s-table-regular" }; String[] rowClass = { "s-table-a", "s-table-b" }; for (Map.Entry<String, Object[]> entry : defaultMap.entrySet()) { String key = entry.getKey(); Object[] e = entry.getValue(); boolean isSet; String value = e[1].toString(); // // the keys // pw.print("<tr class=\""+rowClass[row%rowClass.length]+"\">"); pw.print("<th class=\"s-table\">"); pw.print(key); pw.print("</th>"); // // default values // pw.print("<td class=\"s-table-regular\">"); pw.print("<span class=\"s-table-regular\">"); pw.print(value); pw.println("</span></td>"); // // the other partitions // for (Map<String, Object[]> aRestMap : restMap) { e = aRestMap.get(key); isSet = (Boolean) e[0]; value = e[1].toString(); pw.print("<td class=\"" + setColor[isSet ? 1 : 0] + "\">"); pw.print("<span class=\"" + setColor[isSet ? 1 : 0] + "\">"); pw.println(value); pw.println("</span></td>"); } pw.println("</tr>"); row++; } pw.println("</table></center>"); } private void printParameterInSections(PrintWriter pw, Map<String,Partition> parameterMap) { for (Map.Entry<String,Partition> entry : parameterMap.entrySet()) { String name = entry.getKey(); Partition p = entry.getValue(); pw.println("<h2>"+name+"</h2>"); printParameterEntry(pw, p); } } private void printParameterEntry(PrintWriter pw, Partition p) { Map<String, Object[]> map = p.toMap(); int column = 0; int maxColumn = 2; pw.println("<center><table width=\"90%\" cellspacing=4 cellpadding=4 bgcolor=yellow>"); pw.print("<tr>"); for (int l = 0; l < (maxColumn+1); l ++) { pw.print("<th align=center>Key</th><th align=center>Value</th>"); } pw.println("</tr>"); for (Map.Entry<String, Object[]> entry : map.entrySet()) { String name = entry.getKey(); Object[] array = entry.getValue(); boolean isSet = (Boolean)array[0]; Object value = array[1].toString(); if (column == 0) { pw.print("<tr>"); } String col = isSet ? "black" : "gray"; pw.print("<th bgcolor=white>"); pw.print(name); pw.print("</th>"); pw.print("<td bgcolor=white align=center ><font color="); pw.print(col) ; pw.print(">"); pw.print(value); pw.println("</font></td>"); if (column == maxColumn) { pw.print("</tr>"); } column = (column + 1) % (maxColumn+1); } pw.println("</table></center>"); } private void printLazyRestoreInfo(OutputStream out, String sorting, String grep) { HTMLWriter html = new HTMLWriter(out, _context); html.addHeader("/styles/restoreHandler.css", "dCache Dataset Restore Monitor (Lazy)"); html.beginTable("sortable", "pnfs", "PnfsId", "subnet", "Subnet", "candidate", "PoolCandidate", "started", "Started", "clients", "Clients", "retries", "Retries", "status", "Status"); List<Object[]> copy = new ArrayList<>(_lazyRestoreList); Collections.sort(copy, new OurComparator(sorting)); for (Object[] a: copy) { if ((grep == null) || grepOk(grep, a)) { showRestoreInfo(html, (RestoreHandlerInfo) a[0], (String) a[1], (StorageInfo) a[2]); } } html.endTable(); html.addFooter(getClass().getName()); } private void printRestoreInfo(OutputStream out, String sorting, String grep) { HTMLWriter html = new HTMLWriter(out, _context); html.addHeader("/styles/restoreHandler.css", "dCache Dataset Restore Monitor"); try { RestoreHandlerInfo[] list = _poolManager.sendAndWait("xrc ls", RestoreHandlerInfo[].class); Arrays.sort(list, new OurComparator(sorting)); html.beginTable("sortable", "pnfs", "PnfsId", "subnet", "Subnet", "candidate", "PoolCandidate", "started", "Started", "clients", "Clients", "retries", "Retries", "status", "Status"); for (RestoreHandlerInfo info : list) { if ((grep == null) || grepOk(grep, info)) { showRestoreInfo(html, info); } } html.endTable(); } catch (TimeoutCacheException e) { showTimeout(html); } catch (InterruptedException | CacheException | NoRouteToCellException e) { showProblem(html, e.getMessage()); } html.addFooter(getClass().getName()); } private boolean grepOk(String grep, Object o) { RestoreHandlerInfo info; if (o instanceof RestoreHandlerInfo) { info = (RestoreHandlerInfo)o; } else if (o instanceof Object[]) { info = (RestoreHandlerInfo)((Object[])o)[0]; } else { return true; } StringBuilder sb = new StringBuilder(); sb.append(info.getName()).append(info.getPool()).append(info.getStartTime()).append(info.getStatus()); Object er = info.getErrorMessage(); if (er != null) { sb.append(er.toString()); } if (sb.indexOf(grep) > -1) { return true; } if (!(o instanceof Object[])) { return false; } Object[] a = (Object[])o; if ((a[1] != null) && (a[1].toString().contains(grep))) { return true; } StorageInfo si = (StorageInfo)a[2]; if (si == null) { return false; } return si.toString().contains(grep); } @Override public CellInfo getCellInfo(CellInfo info) { return info; } private static class OurComparator implements Comparator<Object> { private final String _type; private OurComparator(String type) { _type = type; } @Override public int compare(Object o1, Object o2) { if (o1 instanceof RestoreHandlerInfo) { return compareInfo((RestoreHandlerInfo) o1, (RestoreHandlerInfo) o2); } if (o1 instanceof Object[]) { return compareArray((Object[]) o1, (Object[]) o2); } return 0; } private int compareInfo(RestoreHandlerInfo i1, RestoreHandlerInfo i2) { if (_type == null) { return i1.getName().compareTo(i2.getName()); } else if (_type.equals("i.name")) { return i1.getName().compareTo(i2.getName()); } else if (_type.equals("i.error")) { return (i1.getErrorCode() + i1.getName()). compareTo(i2.getErrorCode() + i2.getName()); } else if (_type.equals("i.status")) { return i1.getStatus().compareTo(i2.getStatus()); } else if (_type.equals("i.pool")) { String a = i1.getPool(); String b = i2.getPool(); if ((a == null) || (b == null)) { return a == null ? -1 : b == null ? 1 : 0; } return a.compareTo(b); } else if (_type.equals("i.start")) { return Long.compare(i1.getStartTime(),i2.getStartTime()); } else { return i1.getName().compareTo(i2.getName()); } } private int compareArray(Object[] o1, Object[] o2) { if (_type == null || _type.startsWith("i.")) { return compareInfo((RestoreHandlerInfo) o1[0], (RestoreHandlerInfo) o2[0]); } if (_type.equals("path")) { return o1[1].toString().compareTo(o2[1].toString()); } return compareStorageInfo((StorageInfo) o1[2], (StorageInfo) o2[2]); } private int compareStorageInfo(StorageInfo s1, StorageInfo s2) { if (_type.equals("sclass")) { return s1.getStorageClass().compareTo(s2.getStorageClass()); } String k1 = s1.getKey(_type); String k2 = s2.getKey(_type); if ((k1 == null) || (k2 == null)) { return k1 == null ? -1 : k2 == null ? 1 : 0; } return k1.compareTo(k2); } } private void showRestoreInfo(HTMLWriter html, RestoreHandlerInfo info) { showRestoreInfo(html, info, null, null); } private void showRestoreInfo(HTMLWriter html, RestoreHandlerInfo info, String path, StorageInfo storageInfo) { String name = info.getName(); int pos = name.indexOf('@'); String pnfsId = name.substring(0,pos); String subnet = name.substring(pos+1); int rc = info.getErrorCode(); String msg = info.getErrorMessage(); String started= _formatter.get().format(new Date(info.getStartTime())); boolean error = (rc != 0) || ((msg != null) && (!msg.isEmpty())); String pool = info.getPool(); pool = (pool == null) || (pool.isEmpty() || pool.equals("<unknown>")) ? "N.N." : pool; String status = info.getStatus(); status = (status == null) || (status.isEmpty()) ? " " : status; if (error) { html.beginRow("error", "error odd"); } else { html.beginRow(null, "odd"); } html.td("pnfs", pnfsId); html.td("subnet", subnet); html.td("pool", pool); html.td("started", started); html.td("clients", info.getClientCount()); html.td("retries", info.getRetryCount()); html.td("status", status); if (path != null) { html.endRow(false); if (error) { html.beginRow("error", "error odd"); } else { html.beginRow(null, "odd"); } html.td(7, "path", path); } if (storageInfo != null) { html.endRow(false); if (error) { html.beginRow("error", "error odd"); } else { html.beginRow(null, "odd"); } if (_siDetails != null) { StringBuilder builder = new StringBuilder(); for (String key : _siDetails) { String value; if ((value = storageInfo.getKey(key)) != null) { builder.append(key).append("=").append(value) .append(";"); } } html.td(7, "storageinfo", builder); } else { html.td(7, "storageinfo", storageInfo.toString()); } } if (error) { html.endRow(false); html.beginRow("error", "error odd"); html.td(7, "error", "Code = " + rc + "; Message = " + msg); } html.endRow(); } private void printPoolManagerHeader(PrintWriter pw, String title) { pw.println("<table class=\"m-table\" border=0 cellpadding=10 cellspacing=0 width=\"90%\">"); pw.println("<tr><td align=center valign=center width=\"1%\">"); pw.println("<a href=\"/\"><img border=0 src=\"/images/eagleredtrans.gif\"></a>"); pw.println("<br><font color=red>Birds Home</font>"); pw.println("</td><td align=center>"); if (title != null) { pw.println("<h1>" + title + "</h1>"); } else { pw.println("<h1>Pool Manager Database V3</h1>"); } pw.println("</td></tr></table>"); } private void showDirectory(PrintWriter pw) { showDirectory(pw, -1); } private void showDirectory(PrintWriter pw, int position) { pw.println("<br><center><table class=\"m-table\">"); pw.println("<tr class=\"m-table\">"); printDirEntry(pw, "Partitions" , position == 0, "/poolInfo/parameterHandler/set/matrix/*"); printDirEntry(pw, "Pools" , position == 1, "/poolInfo/pools/*"); printDirEntry(pw, "Pool Groups", position == 2, "/poolInfo/pgroups/*"); printDirEntry(pw, "Selection" , position == 3, "/poolInfo/units/*"); pw.println("</tr><tr>"); printDirEntry(pw, "Selection Groups", position == 4, "/poolInfo/ugroups/*"); printDirEntry(pw, "Links" , position == 5, "/poolInfo/links/*"); printDirEntry(pw, "Link List" , position == 7, "/poolInfo/linklist/*"); printDirEntry(pw, "Match" , position == 6, "/poolInfo/match/*"); pw.println("</tr></table></center>"); pw.println("<br><hr><br>"); } private void printDirEntry(PrintWriter pw, String text, boolean inUse, String link) { String alternateClass=inUse?"class=\"m-table-active\"":"class=\"m-table\""; pw.print("<td width=\"25%\" class=\"m-table\"><span "); pw.print(alternateClass); pw.print("><a "); pw.print(alternateClass); pw.print(" href=\""); pw.print(link); pw.print("\">"); pw.print(text); pw.println("</a></span></td>"); } private void showList(PrintWriter pw, Object[] array, int rows) { showList(pw, array, rows, null); } private void showMatch(PrintWriter pw, HttpRequest request) throws NoRouteToCellException, InterruptedException { String type = request.getParameter(PARAMETER_TYPE); String store = request.getParameter(PARAMETER_STORE); String dcache = request.getParameter(PARAMETER_DCACHE); String net = request.getParameter(PARAMETER_NET); String prot = request.getParameter(PARAMETER_PROTOCOL); String linkGroup = request.getParameter(PARAMETER_LINKGROUP); linkGroup = (linkGroup == null) || (linkGroup.isEmpty()) ? "none" : linkGroup; store = (store == null) || (store.isEmpty()) ? "*" : store; dcache = (dcache == null) || (dcache.isEmpty()) ? "*" : dcache; net = (net == null) || (net.isEmpty()) ? "*" : net; prot = (prot == null) || (prot.isEmpty()) ? "*" : prot; pw.println("<center>"); if (type == null) { showQueryForm(pw, "none", "read", "*", "*", "*", "DCap/3"); } else { showQueryForm(pw, linkGroup, type, store, dcache, net, prot); pw.println("<p><hr><p>"); try { PoolPreferenceLevel[] result = _poolManager.sendAndWait("psux match " + type + " " + store + " " + dcache + " " + net + " " + prot + (linkGroup.equals("none") ? "" : " -linkGroup="+linkGroup), PoolPreferenceLevel[].class); for (int i = 0; i < result.length; i++) { pw.print("<p><h2>Selected Pools with attraction "+i); String tag = result[i].getTag(); if (tag != null) { pw.print(" (dCache subsection=" + tag + ")"); } pw.println("</h2>"); showList(pw, result[i].getPoolList().toArray(), 8, "/poolInfo/pools/"); } } catch (TimeoutCacheException e) { showTimeout(pw); } catch (CacheException e) { showProblem(pw, e.getMessage()); } } pw.println("</center>"); } private String makeLink(String link) { StringBuilder sb = new StringBuilder(); for (int i= 0, n = link.length(); i < n; i ++) { char c = link.charAt(i); switch(c) { case ':' : sb.append("%3A"); break; default : sb.append(c); } } return sb.toString(); } private void showList(PrintWriter pw, Object[] array, int rows, String link) { pw.println("<table class=\"l-table\""); Arrays.sort(array); for (int i= 0; i < array.length; i++) { if ((i % rows) == 0) { pw.println("<tr class=\"l-table\">"); } pw.print("<td class=\"l-table\" "); pw.print("><a class=\"l-table\" href=\""); if (link != null) { pw.print(link); } pw.print(makeLink(array[i].toString())); pw.print("\"><span class=\"l-table\">"); pw.println(array[i].toString()); pw.println("</span>"); pw.println("</a>"); pw.println("</td>"); if ((i % rows) == (rows - 1)) { pw.println("</tr>"); } } int rest = rows - (array.length % rows); if (rest < rows) { for (int i = 0; i < rest; i++) { pw.print("<td class=\"l-table\"><span class=\"l-table\">-</span></td>"); } pw.println("</tr>"); } pw.println("</table>"); } private void showQueryForm(PrintWriter pw, String linkGroup, String type, String store, String dcache, String net, String protocol) { pw.println("<table class=\"f-table-a\">"); pw.println("<tr class=\"f-table-a\">"); pw.println("<td class=\"f-table-a\">"); pw.println("<span class=\"f-table-a\">Simulated I/O Request</span>"); pw.println("</td></tr><tr><td class=\"f-table-a\">"); pw.println("<form method=get action=\"/poolInfo/match/match\">"); pw.println("<table class=\"f-table-b\">"); pw.println("<tr class=\"f-table-b\">"); pw.println("<th class=\"f-table-b\">LinkGroup</th>"); pw.println("<th class=\"f-table-b\">I/O Direction</th>"); pw.println("<th class=\"f-table-b\">Store</th>"); pw.println("<th class=\"f-table-b\">dCache</th>"); pw.println("<th class=\"f-table-b\">Net</th>"); pw.println("<th class=\"f-table-b\">Protocol</th>"); pw.println("</tr><tr>"); pw.println("<td class=\"f-table-b\"><input name=linkGroup value=\""+linkGroup+"\"></td>"); pw.println("<td class=\"f-table-b\">"); pw.println("<select name=type>"); pw.println("<option value=read "+(type.equals("read")?"selected":"")+">Read"); pw.println("<option value=p2p "+(type.equals("p2p")?"selected":"")+">Pool 2 Pool"); pw.println("<option value=cache "+(type.equals("cache")?"selected":"")+">Cache"); pw.println("<option value=write "+(type.equals("write")?"selected":"")+">Write</select>"); pw.println("</td>"); pw.println("<td class=\"f-table-b\"><input name=store value=\""+store+"\"></td>"); pw.println("<td class=\"f-table-b\"><input name=dcache value=\""+dcache+"\"></td>"); pw.println("<td class=\"f-table-b\"><input name=net value=\""+net+"\"></td>"); pw.println("<td class=\"f-table-b\"><input name=protocol value=\""+protocol+"\"></td>"); pw.println("</tr></table>"); pw.println("</td></tr><td class=\"f-table-a\">"); pw.println("<input type=submit value=\"Send Query\">"); pw.println("</form>"); pw.println("</td></tr>"); pw.println("</table>"); } private void queryAll(PrintWriter pw, String request, String type) throws NoRouteToCellException, InterruptedException { try { Object[] o = _poolManager.sendAndWait(request, Object[].class); pw.println("<center><h1>"+type+"</h1>"); showList(pw, o, 8); pw.println("</center>"); } catch (TimeoutCacheException e) { showTimeout(pw); } catch (CacheException e) { showProblem(pw, e.getMessage()); } } private void queryAllPools(PrintWriter pw) throws NoRouteToCellException, InterruptedException { queryAll(pw, "psux ls pool", "Registered Pools"); } private void queryAllPGroups(PrintWriter pw) throws NoRouteToCellException, InterruptedException { queryAll(pw, "psux ls pgroup", "Registered Pool Groups"); } private void queryAllUnits(PrintWriter pw) throws NoRouteToCellException, InterruptedException { queryAll(pw, "psux ls unit", "Registered Units"); } private void queryAllUGroups(PrintWriter pw) throws NoRouteToCellException, InterruptedException { queryAll(pw, "psux ls ugroup", "Registered Unit Groups"); } private void queryAllLinks(PrintWriter pw) throws NoRouteToCellException, InterruptedException { queryAll(pw, "psux ls link", "Registered Links"); } private void queryPool(PrintWriter pw, String poolName) throws NoRouteToCellException, InterruptedException { if ((poolName.isEmpty()) || (poolName.equals("*"))) { queryAllPools(pw); return; } pw.println("<center>"); pw.println("<h1>Report for Pool <font color=red>"+poolName+"</font></h1>"); try { Object[] o = _poolManager.sendAndWait("psux ls pool " + poolName, Object[].class); Object[] groupList = (Object[])o[1]; Object[] linkList = (Object[])o[2]; boolean enabled = (Boolean)o[3]; boolean rdOnly = (Boolean)o[5]; long active = (Long)o[4]; pw.println("<table border=0 cellspacing=4 cellpadding=4>"); pw.print("<tr><th align=right>Enabled : </th><td align=left>"); pw.print(enabled ? "Yes" : "No"); pw.println("</td></tr>"); pw.print("<tr><th align=right>Mode : </th><td align=left>"); pw.print(rdOnly ? "Read Only" : "Read/Write"); pw.println("</td></tr>"); pw.print("<tr><th align=right>Active : </th><td align=left>"); pw.print((active < (60 * 1000)) ? "Yes" : "No"); pw.println("</td></tr></table>"); pw.println("<h3>We are member of the following pool groups</h3>"); showList(pw, groupList, 8, "/poolInfo/pgroups/"); pw.println("<h3>We are pointing to the following Links</h3>"); showList(pw, linkList, 8, "/poolInfo/links/"); } catch (TimeoutCacheException e) { showTimeout(pw); } catch (CacheException e) { showProblem(pw, e.getMessage()); } pw.println("</center>"); } private void queryUnit(PrintWriter pw, String unitName) throws NoRouteToCellException, InterruptedException { if ((unitName.isEmpty()) || (unitName.equals("*"))) { queryAllUnits(pw); return; } pw.println("<center>"); pw.println("<h1>Report for Unit <font color=red>"+unitName+"</font></h1>"); try { Object[] o = _poolManager.sendAndWait("psux ls unit "+unitName, Object[].class); String type = o[1].toString(); Object[] groupList = (Object[])o[2]; pw.println("<table border=0 cellspacing=4 cellpadding=4>"); pw.print("<tr><th align=right>Selection Unit : </th><td align=left>"); pw.print(unitName); pw.println("</td></tr>"); pw.print("<tr><th align=right>Selection Type : </th><td align=left>"); pw.print(type); pw.println("</td></tr>"); pw.print("</table>"); pw.println("<h3>We are member of the following Selection Unit Groups</h3>"); showList(pw, groupList, 8, "/poolInfo/ugroups/"); } catch (TimeoutCacheException e) { showTimeout(pw); } catch (CacheException e) { showProblem(pw, e.getMessage()); } pw.println("</center>"); } private static class LinkProperties implements Comparable<LinkProperties> { private String name; private int readPref; private int writePref; private int cachePref; private int p2pPref; private Object[] groupList; private Object[] poolList; private Object[] pGroupList; private String tag; private LinkProperties(Object[] prop) { extractLinkProperties(this, prop); } private LinkProperties extractLinkProperties(LinkProperties p, Object[] prop) { p.name = prop[0].toString(); p.readPref = (Integer) prop[1]; p.cachePref = (Integer) prop[2]; p.writePref = (Integer) prop[3]; p.p2pPref = (Integer) prop[7]; p.tag = prop[8] == null ? "NONE" : prop[8].toString(); p.groupList = (Object[])prop[4]; p.poolList = (Object[])prop[5]; p.pGroupList = (Object[])prop[6]; return p; } @Override public int compareTo(LinkProperties link ) { if (link.tag.equals(tag)) { return name.compareTo(link.name); } if (tag.equals("NONE")) { return -1; } return tag.compareTo(link.tag); } @Override public String toString() { return "["+tag+"/"+name+"]"; } } private void queryLinkList(PrintWriter pw) throws NoRouteToCellException, InterruptedException { try { List<Object[]> answer = _poolManager.sendAndWait("psux ls link -x", List.class); List<LinkProperties> list = new ArrayList<>(); for (Object[] o : answer) { list.add(new LinkProperties(o)); } Collections.sort(list); pw.println("<center><table class=\"s-table\">"); pw.println("<tr class=\"s-table\">"); pw.print("<th rowspan=2 class=\"s-table\">Name</th>"); pw.print("<th rowspan=2 class=\"s-table\">Partition</th>"); pw.print("<th colspan=4 class=\"s-table\">Preferences</th>"); pw.print("<th colspan=4 rowspan=2 class=\"s-table\">Unit Groups</th>"); pw.print("<th rowspan=2 class=\"s-table\">Pool Groups</th>"); pw.print("<th rowspan=2 class=\"s-table\">Pools</th>"); pw.println("</tr>"); pw.println("<tr class=\"s-table\">"); pw.print("<th class=\"s-table\">Read</th><th class=\"s-table\">Write</font></th>"); pw.print("<th class=\"s-table\">Cache</th><th class=\"s-table\">P2p</font></th>"); pw.println("</tr>"); int row = 0; String[] rowColor = { "s-table-a", "s-table-b" }; for (LinkProperties lp : list) { pw.println("<tr class=\""+rowColor[row%rowColor.length]+"\">"); printLinkPropertyRow(pw, lp); pw.println("</tr>"); row++; } pw.println("</table></center>"); } catch (TimeoutCacheException e) { showTimeout(pw); } catch (CacheException e) { showProblem(pw, e.getMessage()); } } private void printLinkPropertyRow(PrintWriter pw, LinkProperties lp) { String tableData = "<td class=\"s-table\"><span class=\"s-table\">"; String dataEnd = "</span></td>"; pw.print(tableData); pw.print("<a class=\"s-table\" href=\"/poolInfo/links/"); pw.print(lp.name); pw.print("\">"); pw.print(lp.name); pw.println("</a>"+dataEnd); pw.print(tableData); pw.print(lp.tag); pw.println(dataEnd); pw.print(tableData); pw.print(lp.readPref); pw.println(dataEnd); pw.print(tableData); pw.print(lp.writePref); pw.println(dataEnd); pw.print(tableData); pw.print(lp.cachePref); pw.println(dataEnd); if (lp.p2pPref < 0) { pw.print(tableData); pw.print("("+lp.readPref+")"); pw.println(dataEnd); } else { pw.print(tableData); pw.print(lp.p2pPref); pw.println(dataEnd); } int i = 0, n; for (n = lp.groupList == null ? 0 : lp.groupList.length; i < n; i++) { String unitName = lp.groupList[i].toString(); pw.print(tableData); pw.print(unitName); pw.println(dataEnd); } for (; i < 4; i++) { pw.print(tableData); pw.print("-"); pw.println(dataEnd); } StringBuilder sb = new StringBuilder(); if (lp.pGroupList != null) { for (i = 0, n = lp.pGroupList.length; i < n; i++) { sb.append(lp.pGroupList[i]); if (i < (n - 1)) { sb.append(","); } } } String out = sb.length() == 0 ? "-" : sb.toString(); pw.print(tableData); pw.print(out); pw.println(dataEnd); sb = new StringBuilder(); if (lp.poolList != null) { for (i = 0, n = lp.poolList.length; i < n; i++) { sb.append(lp.poolList[i]); if (i < (n - 1)) { sb.append(","); } } } out = sb.length() == 0 ? "-" : sb.toString(); pw.print(tableData); pw.print(out); pw.println(dataEnd); } private void queryLink(PrintWriter pw, String linkName) throws NoRouteToCellException, InterruptedException { if ((linkName.isEmpty()) || (linkName.equals("*"))) { queryAllLinks(pw); return; } try { Object[] answer = _poolManager.sendAndWait("psux ls link " + linkName, Object[].class); LinkProperties lp = new LinkProperties(answer); pw.println("<center>"); pw.println("<h1>Report for Link <font color=red>"+linkName+"</font></h1>"); pw.println("<h3>Link Properties</h3>"); pw.println("<table class=\"s-table\" id=\"linkproperties\">"); pw.println("<tr class=\"s-table\">"); pw.println("<th class=\"s-table\" colspan=4>Preferences</td>"); pw.println("<th rowspan=2 align=center class=\"s-table\">dCache Partition</td></tr>"); pw.println("<tr class=\"s-table\">"); pw.println("<th class=\"s-table\">Read</th>"); pw.println("<th class=\"s-table\">Write</th>"); pw.println("<th class=\"s-table\">Restore</th>"); pw.println("<th class=\"s-table\">Pool to Pool</th>"); pw.println("</tr>"); pw.print("<tr class=\"s-table-b\">"); pw.print("<td class=\"s-table\"><span class=\"s-table\">"); pw.print(lp.readPref); pw.println("</span></td>"); pw.print("<td class=\"s-table\"><span class=\"s-table\">"); pw.print(lp.writePref); pw.println("</span></td>"); pw.print("<td class=\"s-table\"><span class=\"s-table\">"); pw.print(lp.cachePref); pw.println("</span></td>"); pw.print("<td class=\"s-table\"><span class=\"s-table\">"); pw.print(lp.p2pPref); pw.println("</span></td>"); pw.print("<td class=\"s-table\"><span class=\"s-table\">"); pw.print(lp.tag); pw.println("</span></td>"); pw.print("<tr>"); pw.println("</table>"); if (lp.poolList.length > 0) { pw.println("<h3>We point the following Pools</h3>"); showList(pw, lp.poolList, 8, "/poolInfo/pools/"); } pw.println("<h3>We point to the following Pool Groups</h3>"); showList(pw, lp.pGroupList, 8, "/poolInfo/pgroups/"); pw.println("<h3>We point to the following Selection Unit Groups</h3>"); showList(pw, lp.groupList, 8, "/poolInfo/ugroups/"); pw.println("</center>"); } catch (TimeoutCacheException e) { showTimeout(pw); } catch (CacheException e) { showProblem(pw, e.getMessage()); } } private void queryUnitGroup(PrintWriter pw, String groupName) throws NoRouteToCellException, InterruptedException { if ((groupName.isEmpty()) || (groupName.equals("*"))) { queryAllUGroups(pw); return; } pw.println("<center>"); pw.println("<h1>Report for Unit Group <font color=red>"+groupName+"</font></h1>"); try { Object[] o = _poolManager.sendAndWait("psux ls ugroup "+groupName, Object[].class); Object[] unitList = (Object[])o[1]; Object[] linkList = (Object[])o[2]; pw.println("<table border=0 cellspacing=4 cellpadding=4>"); pw.print("<tr><th align=right>Unit Group : </th><td align=left>"); pw.print(groupName); pw.println("</td></tr>"); pw.print("</table>"); pw.println("<h3>We have the following Members</h3>"); showList(pw, unitList, 8, "/poolInfo/units/"); pw.println("<h3>We are pointing to the following links</h3>"); showList(pw, linkList, 8, "/poolInfo/links/"); } catch (TimeoutCacheException e) { showTimeout(pw); } catch (CacheException e) { showProblem(pw, e.getMessage()); } pw.println("</center>"); } private void queryPoolGroup(PrintWriter pw, String groupName) throws NoRouteToCellException, InterruptedException { if ((groupName.isEmpty()) || (groupName.equals("*"))) { queryAllPGroups(pw); return; } pw.println("<center>"); pw.println("<h1>Report for Pool Group <font color=red>"+groupName+"</font></h1>"); try { Object[] o = _poolManager.sendAndWait("psux ls pgroup "+groupName, Object[].class); Object[] poolList = (Object[])o[1]; Object[] linkList = (Object[])o[2]; pw.println("<table border=0 cellspacing=4 cellpadding=4>"); pw.print("<tr><th align=right>Pool Group : </th><td align=left>"); pw.print(groupName); pw.println("</td></tr>"); pw.print("</table>"); pw.println("<h3>We have the following Members</h3>"); showList(pw, poolList, 8, "/poolInfo/pools/"); pw.println("<h3>We are pointing to the following links</h3>"); showList(pw, linkList, 8, "/poolInfo/links/"); } catch (TimeoutCacheException e) { showTimeout(pw); } catch (CacheException e) { showProblem(pw, e.getMessage()); } pw.println("</center>"); } private void showTimeout(PrintWriter pw) { pw.println("<font color=red><h1>Sorry, the request timed out</h1></font>"); } private void showProblem(PrintWriter pw, String message) { pw.print("<font color=red><h1>"); pw.print(message); pw.println("</h1></font>"); } }