Installing JAMon



http://jamonapi.sourceforge.net/

Jamon is a tool to get response time from java application.
It helps debugging and getting stats on user experience etc...

Installation


  • add JAMon.jar to your [WEBAPP_HOME]/web-inf/lib

  • Create a class for the filter servlet
ie : [WEBAPP_HOME]/src/com/pcf/JAMonServletFilter.java

JAMonServletFilter.java
package com.pcf.isa.util;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import com.jamonapi.*;

/**
 * This filter is registered by web.xml
 * Once registered all web server request pass through here.
 * 
 * @author thibautc
 * Oct 21, 2005 9:07:05 AM
 * Copyright Pacific Coast Feather
 */
public class JAMonServletFilter extends HttpServlet implements Filter {
     private FilterConfig filterConfig;

     //Handle the passed-in FilterConfig
     public void init(FilterConfig filterConfig) {
       this.filterConfig = filterConfig;
     }

     //Process the request/response pair
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
      throws IOException, ServletException {
       // monitor page hits and processing time
       Monitor monitor = MonitorFactory.start(getURI(request));

       try {
       //call next filter in chain
        filterChain.doFilter(request, response);
       }
       finally {
        monitor.stop();
       }
     }

     protected String getURI(ServletRequest request){
       if (request instanceof HttpServletRequest) {
        return ((HttpServletRequest)request).getRequestURI();
       }
       else
        return "Not an HttpServletRequest";
     }

     //Clean up resources
     public void destroy() {
       filterConfig=null;
     }

}


  • add a servlet filter to [WEBAPP_HOME]/web-inf/web.xml

[WEBAPP_HOME]/web-inf/web.xml
<filter>
		<filter-name>JAMonFilter</filter-name>
		<filter-class>com.pcf.isa.util.JAMonServletFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>JAMonFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>



Copy the jamon folder (containing the resources: images, jsp's etc ...) to:
[WEBAPP_HOME]/web/ (or wherever is your content root: ie where you have your html and jsp's)

Using JAMon



Edit your java code like this (example):

// other imports
import com.jamonapi.*;

// Beginning of a method
Monitor mon=MonitorFactory.start("MyMethodName");
// method content to be "timed"
mon.stop();	
// 


After deploying the webapp, you can go see the stats:
http://localhost:8080/myapp/jamon/JAMonAdmin.jsp


Problem with Jamon2 JMOnAdmin.jsp


With the new version oj JAMon (jamon2) i had issues with the JAMonAdmin.jsp not working (blank page)
I haven't had much time to find what the exact problem was, but after removing the xml output code from it and also moving the java functions declarations to the top (where they should be) i got it to work.

Here is my "fixed" JMONadmin.jsp:
JMONadmin.jsp
<%@ page language="java" buffer="8kb" autoFlush="true" isThreadSafe="true" isErrorPage="false"  %>
<%@ page import="java.util.*, java.text.*, com.jamonapi.*, com.jamonapi.utils.*, com.fdsapi.*, com.fdsapi.arrays.*" %>

<%!

String[] actionHeader={"action","actionDisplay"};
Object[][] actionBody={
                 {"Refresh", "Refresh"}, 
                 {"Reset", "Reset"}, 
	           {"Enable","Enable"}, 
	           {"Disable","Disable"}, 
                };


String[] displayTypeHeader={"displayTypeValue","displayType"};
Object[][] displayTypeBody={
                 {"RangeColumns", "Basic/Range Cols"}, 
                 {"BasicColumns", "Basic Cols Only"}, 
	           {"AllColumns","All Cols"}, 
                };

String[] outputTypeHeader={"outputTypeValue","outputType"};
Object[][] outputTypeBody={
                 {"html", "HTML"}, 
                 {"xml", "XML"}, 
	           {"excel","MS Excel"}, 
                };


FormattedDataSet fds=new FormattedDataSet();
Template jamonTemplate;

String[] formatHeader={"formatterValue","formatterDisplay"};
Object[][] formatBody= {
                       {"#,###","#,###"},
                       {"#,###.#","#,###.#"},
                       {"#,###.##","#,###.##"},
                       {"#,###.###","#,###.###"},
                       {"#,###.####","#,###.####"},
                       {"raw","No Format"},  
                      };

// Format time String in current locale.
private String now() {
  return LocaleContext.getDateFormatter().format(new Date());
}


private synchronized Template getJAMonTemplate() {
   // start from sortedHTMLTable template and add some jamon display capabilities (highlighting and descriptive text appearing where the mouse is)
   if (jamonTemplate==null) {
     jamonTemplate=fds.getTemplate("sortedHTMLTable").copy();

     // highlighting for odd and even rows of the JAMon report.  Affects coloring, 
     // and what happens when the rows is highlighted with the mouse.
     String odd="Odd==   <tr class='odd' onMouseOver='rollOnRow(this, \"##1\")' onMouseOut='rollOffRow(this)'>\n";
     String even="Even==   <tr class='even' onMouseOver='rollOnRow(this, \"##1\")' onMouseOut='rollOffRow(this)'>\n";
     jamonTemplate.initialize("BODY_ROW_PREFIX",0,0,"Type==Alternating "+odd+" "+even);
   }

   return jamonTemplate;
}


// if the value is null then return the passed in default else return the value
private static String getValue(String value, String defaultValue) {
  return (value==null || "".equals(value.trim())) ? defaultValue: value;
}

// convert arg to an int or return the default
private static int getSortCol(String value, String defaultValue) {
  String col=getValue(value, defaultValue);
  return Integer.parseInt(col);
}

private static ResultSetConverter getResultSetConverter(String[] header, Object[][] data, String arraySQLExec) {
     ArraySQL asql=new ArraySQL(header, arraySQLExec );
     ArrayConverter ac=new ArrayConverter();

     // replace all booleans with strings as you can't sort booleans (they don't support Comparable interface for some reason)
     Map map=new HashMap();
     map.put(new Boolean(true), "true");
     map.put(new Boolean(false), "false");

     ac.setDefaultConverter(new ConverterMapValue(map));
     asql.setArrayConverter(ac);

     ResultSetConverter rsc = new ResultSetConverter(header, asql.convert(data));
     //MonitorFactory.add("cellCount","count",rsc.getColumnCount()*rsc.getRowCount());
     return rsc;
}

private static Map getDefaultsMap() {
  Map map=new HashMap();

  Double max=new Double(-Double.MAX_VALUE);
  Double min=new Double(Double.MAX_VALUE);
  Date noDate=new Date(0);

  map.put(min,"");
  map.put(max,"");
  map.put(noDate,"");

  return map;
}


private static ArrayConverter getArrayConverter(String pattern) {
  if (pattern==null || "".equals(pattern))
    pattern="#,###";
  else if ("raw".equalsIgnoreCase(pattern)) {
    ArrayConverter ac=new ArrayConverter();
    ac.setDefaultConverter(new NullConverter());
    return ac;
  }

  // used to format the data in the report
  ArrayConverter ac=new ArrayConverter();
  // replace the normal extreme values of default min,max, and acccess date with an empty default.
  // If the key is in the data stream the value will be used instead of the key.
  Map map=getDefaultsMap();

  DecimalFormat decimalFormat=LocaleContext.getFloatingPointFormatter();
  decimalFormat.applyPattern(pattern);
  DateFormat dateFormat=LocaleContext.getDateFormatter();

  // Set the converter to take action on data passed to the FormattedDataSet
  ac.setDefaultConverter(new ConverterNumToString(decimalFormat, new ConverterDateToString(dateFormat, new ConverterMapValue(map))));
 
  return ac;

}


// This version of the FormattedDataSet requires a value as well as the display value.  The same column is used for both 
// below.
private static Object[][] getRangeNames() {
   Object[][] range=MonitorFactory.getRangeNames();
   Object[][] data=new Object[range.length][];
   for (int i=0;i<range.length;i++) {
      data[i]=new Object[2];
      data[i][0]=data[i][1]=range[i][0];
   }
  
   return data;
     

}
%>


<%

// Set formatting rules per the requests Locale (as opposed to the servers locale).
// This will format data per the users preference (note this sets it for the given thread/servlet)
LocaleContext.setLocale(request.getLocale());

// Assign request parameters to local variables.
String action    = getValue(request.getParameter("action"),"Refresh");
String outputType= getValue(request.getParameter("outputTypeValue"),"html");
String formatter = getValue(request.getParameter("formatterValue"), "#,###");
String arraySQL  = getValue(request.getParameter("ArraySQL"),"");
String sortOrder = getValue(request.getParameter("sortOrder"), "asc");
int sortCol      = getSortCol(request.getParameter("sortCol"), "1");

// Assign defaults to RangeName and displayTypeValue if they weren't part of the request.
String displayType=getValue(request.getParameter("displayTypeValue"), "BasicColumns");
String rangeName=getValue(request.getParameter("RangeName"),"AllMonitors");

// AllMonitors can't display ranges so allways change displayType to BasicColumns in this case
displayType=(rangeName.equalsIgnoreCase("AllMonitors")) ? "BasicColumns" : displayType;

// Assign defaults for arraysql.  If nothing is provided use 'select * from array'.  If the first word is not 
// 'select' assume they want to do a like on the first column (label).
String arraySQLExec = getValue(arraySQL,"select * from array");

if (arraySQLExec.trim().toLowerCase().startsWith("select")) 
  arraySQLExec=arraySQLExec;// noop all is ok full select entered
else if (arraySQLExec.trim().toLowerCase().startsWith("where")) 
   arraySQLExec="select * from array "+arraySQL;// where clause entered:  where hits>100 and total<50000
else
   arraySQLExec="select * from array where col0 like '"+arraySQL+"'";

arraySQLExec = (arraySQLExec.trim().toLowerCase().startsWith("select")) ? arraySQLExec : "select * from array where col0 like '"+arraySQL+"'";

// Build the request parameter query string that will be part of every clickable column.
String query="";
query+="&displayTypeValue="+displayType;
query+="&RangeName="+rangeName;
query+="&outputTypeValue="+outputType;
query+="&formatterValue="+java.net.URLEncoder.encode(formatter);
query+="&ArraySQL="+java.net.URLEncoder.encode(arraySQL);


if ("Reset".equals(action))
    MonitorFactory.reset();
else if ("Enable".equals(action)) 
    MonitorFactory.setEnabled(true);
else if ("Disable".equals(action))  
    MonitorFactory.setEnabled(false);

Map map=new HashMap();
// used for html page
map.put("sortPageName", "JAMonAdmin.jsp");
map.put("query", query);
map.put("imagesDir","images/");


// used for xml1 page.
map.put("rootElement", "JAMonXML");


String outputText;
MonitorComposite mc=MonitorFactory.getComposite(rangeName);

if (!MonitorFactory.isEnabled())
  outputText="<div align='center'><br><br><b>JAMon is currently disabled.  To enable monitoring you must select 'Enable'</b></div>";
else if (!mc.hasData())
  outputText="<div align='center'><br><br><b>No data was returned</b></div>";
else {
  ResultSetConverter rsc;  // contains the header, and data after ArraySQL is applied.  This is a thin wrapper for arrays.

  if (displayType.equalsIgnoreCase("BasicColumns") || rangeName.equalsIgnoreCase("AllMonitors")) 
     rsc=getResultSetConverter(mc.getBasicHeader(), mc.getBasicData(), arraySQLExec);
  else if (displayType.equalsIgnoreCase("RangeColumns")) 
     rsc=getResultSetConverter(mc.getDisplayHeader(), mc.getDisplayData(), arraySQLExec);
  else if (displayType.equalsIgnoreCase("AllColumns")) 
     rsc=getResultSetConverter(mc.getHeader(), mc.getData(), arraySQLExec);
  else 
     rsc=getResultSetConverter(mc.getBasicHeader(), mc.getBasicData(), arraySQLExec);

  if (rsc.isEmpty())
    outputText="<div align='center'><br><br><b>No data was returned</b></div>";
  else {
    ArrayConverter ac=getArrayConverter(formatter);
    fds.setArrayConverter(ac);

    if ("xml".equalsIgnoreCase(outputType)) {
      rsc=new ResultSetConverter(rsc.getMetaData(), ac.convert(rsc.getResultSet()));
      outputText=fds.getFormattedDataSet(rsc, map, "xml1");
    }
    else if ("excel".equalsIgnoreCase(outputType) || "spreadsheet".equalsIgnoreCase(outputType)) {
      rsc=new ResultSetConverter(rsc.getMetaData(), ac.convert(rsc.getResultSet()));
      outputText=fds.getFormattedDataSet(rsc, map, "basicHtmlTable");
    }
    else 
      outputText=fds.getSortedText(rsc.getMetaData(), rsc.getResultSet(), map, sortCol, sortOrder, getJAMonTemplate());

  }
}


%>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<head>
<META http-equiv="Content-Type" content="text/html"; charset=ISO-8859-1">
<link rel="stylesheet" type="text/css" href="css/JAMonStyles.css">
<title>JAMon - Administration/Reporting - <%=now()%></title>
<script type="text/javascript">
<!--
// Row highlighter
var objClass

function rollOnRow(obj, txt) {
    objClass = obj.className
    obj.className = "rowon";
    obj.title = txt;
}

function rollOffRow(obj) {
    obj.className = objClass;
}

function selectAll(obj, numRows) {
    state = (obj.checked) ? true : false;

    for (var i = 1; i < numRows + 1; i ++) {
        currRow = eval("obj.form.row_" + i);
        currRow.checked = state;
    }
}

function helpWin() {
    newWin = window.open('JAMonHelp.htm', 'helpWin', 'resizable=no,scrollbars=yes,height=550,width=450,screenX=100,screenY=100');
    if (newWin.opener == null) newWin.opener = self;
}
// -->
</script>

</head>
<body>

<!-- arraySQLExec=<%=arraySQLExec%>-->

<form action="JAMonAdmin.jsp" method="post">

<table border="0" cellpadding="1" cellspacing="0" align="center">
<tr>
<td><h2 style="color:#03487F;">JAMon - Administration/Reporting - <%=now()%></h2></td>
</tr>
<tr>
<td><table class="layoutmain" border="0" cellpadding="4" cellspacing="0" width="750" align="left">
    <tr class="sectHead">
    <th>Action</th>
    <th>Output</th>
    <th>Range/Units</th>
    <th>Display Columns</th>
    <th>Cell Format</th>
    <th>Filter (optional)</th>
    <th align="right"><a href="javascript:helpWin();" style="color:#C5D4E4;">Help</a></th>
    </tr>
    <tr class="even">
    <th><%=fds.getDropDownListBox(actionHeader, actionBody, action)%></th>
    <th><%=fds.getDropDownListBox(outputTypeHeader, outputTypeBody, outputType)%></th>
    <th><%=fds.getDropDownListBox(MonitorFactory.getRangeHeader(), getRangeNames(), rangeName)%></th>
    <th><%=fds.getDropDownListBox(displayTypeHeader, displayTypeBody, displayType)%></th>
    <th><%=fds.getDropDownListBox(formatHeader, formatBody, formatter)%></th>
    <th><input type='text' name='ArraySQL' value="<%=arraySQL%>" size="45"></th>
    <td><input type="submit" name="actionSbmt" value="Go !" ></td>
    </tr>
</table></td>
</tr>
<tr>
<td><table border="0" cellpadding='0' cellspacing='0' align="center">
    <tr>
    <td><%=outputText%></td>
    </tr>
</table></td>
</tr>
</table>

</form>

<hr width="75%">

<td><table border='0' align='center' width='25%'>
    <tr>
    <th nowrap><a href="http://www.jamonapi.com"><img src="images/jamon_small.jpg" id="monLink" border="0" /></a></th>
    <th nowrap>JAMon <%=MonitorFactory.getVersion()%></th>
    <th nowrap><a href="http://www.fdsapi.com"><img height=40 width=80 src="images/fds_logo_small.jpg" id="monLink" border="0" /></a></th>
    </tr>
</table></td>


</body>



Comments

Add a new Comment