package diskCacheV111.cells; import java.io.OutputStream; import java.util.Map; import java.util.TreeMap; import diskCacheV111.util.CacheException; import diskCacheV111.util.HTMLWriter; import diskCacheV111.util.TimeoutCacheException; import dmg.cells.nucleus.CellEndpoint; import dmg.cells.nucleus.CellMessageSender; import dmg.cells.nucleus.CellPath; import dmg.cells.nucleus.DomainContextAware; import dmg.cells.nucleus.NoRouteToCellException; import dmg.util.HttpException; import dmg.util.HttpRequest; import dmg.util.HttpResponseEngine; import org.dcache.cells.CellStub; import org.dcache.util.Args; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Strings.isNullOrEmpty; import static java.util.concurrent.TimeUnit.SECONDS; public class HttpBillingEngine implements HttpResponseEngine, CellMessageSender, DomainContextAware { private final String _billingAddress; private CellStub _billing; private Map<String, Object> _context; public HttpBillingEngine(String[] args) { Args arguments = new Args(args); _billingAddress = arguments.getOption("billing"); checkArgument(!isNullOrEmpty(_billingAddress), "billing option is required"); } @Override public void startup() { // No background activity to start } @Override public void shutdown() { // No background activity to shutdown } @Override public void setCellEndpoint(CellEndpoint endpoint) { _billing = new CellStub(endpoint, new CellPath(_billingAddress), 5, SECONDS); } @Override public void setDomainContext(Map<String, Object> context) { _context = context; } private void printTotalStatistics(HTMLWriter out, Object [][] x) { out.println("<h2>Total Request Overview</h2>"); out.beginTable("sortable", "action", "Action", "count", "Total Request Count", "failures", "Request Failed"); for (Object[] y : x) { String key = (String)y[0]; int [] z = (int [])y[1]; out.beginRow(null, "odd"); out.th("action", key); out.td("count", z[0]); out.td("failures", z[1]); out.endRow(); } out.endTable(); } private void printPoolStatistics(HTMLWriter out, Map<String, long[]> map, String pool) { boolean perPool = pool != null ; out.print("<h2>Pool Statistics"); if (perPool) { out.println(" of " + pool); } out.println("</h2>"); if (perPool) { out.beginTable("sortable", "pool_storageclass", "StorageClass", "pool_transfers", "Mover Transfers", "pool_restores", "Restores from HSM", "pool_stores", "Stores to HSM", "pool_errors", "Total Errors"); } else { out.beginTable("sortable", "pool_pool", "Pool", "pool_transfers", "Mover Transfers", "pool_restores", "Restores from HSM", "pool_stores", "Stores to HSM", "pool_errors", "Total Errors"); } long [] total = new long[4] ; for (Map.Entry<String, long[]> entry : new TreeMap<>(map).entrySet()) { String s = entry.getKey(); long [] counters = entry.getValue(); out.beginRow(null, "odd"); if (perPool) { out.th("pool_storageclass", s); } else { out.th("pool_pool", "<a href=\"pool/" + s + "\">" + s + "</a>"); } out.td("pool_transfers", counters[0]); out.td("pool_restores", counters[1]); out.td("pool_stores", counters[2]); out.td("pool_errors", counters[3]); total[0] += counters[0]; total[1] += counters[1]; total[2] += counters[2]; total[3] += counters[3]; out.endRow(); } // // total count // out.beginRow("total"); out.th("total", "Total"); out.td("pool_transfers", total[0]); out.td("pool_restores", total[1]); out.td("pool_stores", total[2]); out.td("pool_errors", total[3]); out.endRow(); out.endTable(); } private void printPerPoolStatisticsPage(OutputStream out, String pool) { HTMLWriter html = new HTMLWriter(out, _context); try { html.addHeader("/styles/billing.css", "dCache Billing"); Map<String, long[]> map = _billing.sendAndWait("get pool statistics " + pool, Map.class); printPoolStatistics(html, map, pool); } catch (NoRouteToCellException e) { html.print("<blockquote><pre>No connection to billing</pre></blockquote>"); } catch (TimeoutCacheException e) { html.print("<blockquote><pre>Request Timed Out</pre></blockquote>"); } catch (InterruptedException | CacheException e) { html.print("<blockquote><pre>" + e + "</pre></blockquote>"); } finally { html.addFooter(getClass().getName()); } } private void printMainStatisticsPage(OutputStream out) throws HttpException { HTMLWriter html = new HTMLWriter(out, _context); try { Object[][] x = _billing.sendAndWait("get billing info", Object[][].class); html.addHeader("/styles/billing.css", "dCache Billing"); printTotalStatistics(html, x); try { Map<String, long[]> map = _billing.sendAndWait("get pool statistics", Map.class); printPoolStatistics(html, map, null); } catch (InterruptedException | TimeoutCacheException e) { throw e; } catch (CacheException e) { html.print("<p class=\"error\">This 'billingCell' doesn't support: 'get pool statistics':"); html.print("<blockquote><pre>" + e + "</pre></blockquote>"); } } catch (NoRouteToCellException e) { throw new HttpException(500, "No connection to billing"); } catch (TimeoutCacheException e) { throw new HttpException(500, "Request Timed Out"); } catch (InterruptedException | CacheException e) { throw new HttpException(500, "Problem : " + e.getMessage()); } finally { html.addFooter(getClass().getName()); } } @Override public void queryUrl(HttpRequest request) throws HttpException { OutputStream out = request.getOutputStream(); String [] urlItems = request.getRequestTokens(); int offset = request.getRequestTokenOffset(); // System.out.println( "UrlItem (offset) "+offset ) ; // for( int i = 0 ; i < urlItems.length ; i++ ) // System.out.println("UrlItem : "+i+" "+urlItems[i] ) ; request.printHttpHeader(0); int argc = urlItems.length - offset ; if (argc > 0) { if (urlItems[offset].equals("pool") && (argc > 1)) { printPerPoolStatisticsPage(out, urlItems[offset + 1]); } } else { printMainStatisticsPage(out); } } }