mirror of https://github.com/mchr3k/org.intrace
Add download counters to the GAE site
This commit is contained in:
parent
59960565ee
commit
b3ea5ba6bc
|
|
@ -8,4 +8,6 @@ asm3.2_*
|
|||
asm_patch*
|
||||
libsrc*
|
||||
*private*
|
||||
*genfile*
|
||||
*genfile*
|
||||
classes/
|
||||
appengine-generated/
|
||||
|
|
@ -3,5 +3,8 @@
|
|||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="com.google.appengine.eclipse.core.GAE_CONTAINER"/>
|
||||
<classpathentry kind="lib" path="lib/junit-4.10.jar"/>
|
||||
<classpathentry kind="lib" path="war/WEB-INF/lib/joda-time-2.0.jar"/>
|
||||
<classpathentry kind="src" path="testsrc"/>
|
||||
<classpathentry kind="output" path="war/WEB-INF/classes"/>
|
||||
</classpath>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#Mon Nov 07 21:54:15 GMT 2011
|
||||
#Sun Nov 13 21:28:21 GMT 2011
|
||||
eclipse.preferences.version=1
|
||||
filesCopiedToWebInfLib=
|
||||
filesCopiedToWebInfLib=appengine-api-1.0-sdk-1.5.5.jar|appengine-api-labs-1.5.5.jar|appengine-jsr107cache-1.5.5.jar|jsr107cache-1.1.jar|datanucleus-appengine-1.0.9.final.jar|datanucleus-core-1.1.5.jar|datanucleus-jpa-1.1.5.jar|geronimo-jpa_3.0_spec-1.1.1.jar|geronimo-jta_1.1_spec-1.1.1.jar|jdo2-api-2.3-eb.jar
|
||||
gaeDeployDialogSettings=
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -0,0 +1,76 @@
|
|||
package org.gaecounter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.jdo.PersistenceManager;
|
||||
import javax.jdo.Query;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.gaecounter.data.Counter;
|
||||
import org.gaecounter.data.PMF;
|
||||
|
||||
public class ActionServlet extends HttpServlet
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest xiReq,
|
||||
HttpServletResponse xiResp)
|
||||
throws ServletException,
|
||||
IOException
|
||||
{
|
||||
String lAction = xiReq.getParameter("action");
|
||||
String lRedir = xiReq.getParameter("redir");
|
||||
|
||||
if ("clear".equals(lAction) ||
|
||||
"clearfile".equals(lAction))
|
||||
{
|
||||
PersistenceManager pm = PMF.get().getPersistenceManager();
|
||||
try
|
||||
{
|
||||
Query lDeletion = pm.newQuery(Counter.class);
|
||||
if ("clearfile".equals(lAction))
|
||||
{
|
||||
String lFile = Utils.dec(xiReq.getParameter("file"));
|
||||
lDeletion.setFilter("mFile == mFilenameParam");
|
||||
lDeletion.declareParameters("String mFilenameParam");
|
||||
lDeletion.deletePersistentAll(lFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
lDeletion.deletePersistentAll();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
pm.close();
|
||||
}
|
||||
}
|
||||
else if ("testdata".equals(lAction))
|
||||
{
|
||||
CountDownloadsFilter.countDownload("test_0.1.jar", 2010, 1, 1);
|
||||
CountDownloadsFilter.countDownload("test_0.1.jar", 2010, 1, 1);
|
||||
CountDownloadsFilter.countDownload("test_0.1.jar", 2010, 1, 2);
|
||||
CountDownloadsFilter.countDownload("test_0.1.jar", 2010, 2, 2);
|
||||
CountDownloadsFilter.countDownload("test_0.1.jar", 2010, 3, 2);
|
||||
CountDownloadsFilter.countDownload("test_0.2.jar", 2010, 4, 2);
|
||||
CountDownloadsFilter.countDownload("test_0.2.jar", 2010, 5, 2);
|
||||
CountDownloadsFilter.countDownload("test_0.2.jar", 2010, 5, 2);
|
||||
CountDownloadsFilter.countDownload("test_0.2.jar", 2010, 6, 2);
|
||||
CountDownloadsFilter.countDownload("test_0.3.jar", 2011, 1, 1);
|
||||
CountDownloadsFilter.countDownload("test_0.3.jar", 2011, 1, 1);
|
||||
CountDownloadsFilter.countDownload("test_0.3.jar", 2011, 1, 2);
|
||||
CountDownloadsFilter.countDownload("test_0.3.jar", 2011, 2, 2);
|
||||
CountDownloadsFilter.countDownload("test_0.3.jar", 2011, 3, 2);
|
||||
CountDownloadsFilter.countDownload("test_0.4.jar", 2011, 4, 2);
|
||||
CountDownloadsFilter.countDownload("test_0.4.jar", 2011, 5, 2);
|
||||
CountDownloadsFilter.countDownload("test_0.4.jar", 2011, 5, 2);
|
||||
CountDownloadsFilter.countDownload("test_0.4.jar", 2011, 6, 2);
|
||||
}
|
||||
|
||||
xiResp.sendRedirect(lRedir);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
package org.gaecounter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.jdo.JDOCanRetryException;
|
||||
import javax.jdo.JDOObjectNotFoundException;
|
||||
import javax.jdo.PersistenceManager;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.gaecounter.data.Counter;
|
||||
import org.gaecounter.data.Counter.Type;
|
||||
import org.gaecounter.data.PMF;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
public class CountDownloadsFilter implements Filter
|
||||
{
|
||||
@Override
|
||||
public void init(FilterConfig xiConfig) throws ServletException
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest xiReq,
|
||||
ServletResponse xiResp,
|
||||
FilterChain xiChain)
|
||||
throws IOException,
|
||||
ServletException
|
||||
{
|
||||
if (xiReq instanceof HttpServletRequest)
|
||||
{
|
||||
HttpServletRequest lHttpReq = (HttpServletRequest)xiReq;
|
||||
String lReqURI = lHttpReq.getRequestURI();
|
||||
DateTime lNow = new DateTime();
|
||||
countDownload(lReqURI, lNow.getYear(), lNow.getMonthOfYear(), lNow.getDayOfMonth());
|
||||
if (lReqURI.endsWith(".so"))
|
||||
{
|
||||
xiResp.setContentType("application/octet-stream");
|
||||
}
|
||||
}
|
||||
xiChain.doFilter(xiReq, xiResp);
|
||||
}
|
||||
|
||||
public static void countDownload(String xiReqURI, int y, int m, int d)
|
||||
{
|
||||
String lYStr = Type.YEAR.getPartialStr(y, m, d);
|
||||
String lYStrKey = Counter.getKey(xiReqURI, lYStr);
|
||||
String lYMStr = Type.MONTH.getPartialStr(y, m, d);
|
||||
String lYMStrKey = Counter.getKey(xiReqURI, lYMStr);
|
||||
String lYMDStr = Type.DAY.getPartialStr(y, m, d);
|
||||
String lYMDStrKey = Counter.getKey(xiReqURI, lYMDStr);
|
||||
|
||||
PersistenceManager pm = PMF.get().getPersistenceManager();
|
||||
try
|
||||
{
|
||||
incrementCounter(pm, lYStrKey, Type.YEAR, lYStr, xiReqURI);
|
||||
incrementCounter(pm, lYMStrKey, Type.MONTH, lYMStr, xiReqURI);
|
||||
incrementCounter(pm, lYMDStrKey, Type.DAY, lYMDStr, xiReqURI);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pm.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void incrementCounter(PersistenceManager xiPm,
|
||||
String xiKey,
|
||||
Type xiType,
|
||||
String xiDateStr,
|
||||
String xiReqURI)
|
||||
{
|
||||
try
|
||||
{
|
||||
int retries = 0;
|
||||
int NUM_RETRIES = 10;
|
||||
while (true) // break out below
|
||||
{
|
||||
retries++;
|
||||
|
||||
xiPm.currentTransaction().begin();
|
||||
|
||||
Counter lCounter = null;
|
||||
try
|
||||
{
|
||||
lCounter = xiPm.getObjectById(Counter.class, xiKey);
|
||||
lCounter.incrementCount();
|
||||
}
|
||||
catch (JDOObjectNotFoundException ex)
|
||||
{
|
||||
lCounter = new Counter(xiType, xiDateStr, xiReqURI);
|
||||
}
|
||||
xiPm.makePersistent(lCounter);
|
||||
|
||||
try
|
||||
{
|
||||
xiPm.currentTransaction().commit();
|
||||
break;
|
||||
}
|
||||
catch (JDOCanRetryException ex)
|
||||
{
|
||||
if (retries == NUM_RETRIES)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (xiPm.currentTransaction().isActive())
|
||||
{
|
||||
xiPm.currentTransaction().commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package org.gaecounter;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
public class Utils
|
||||
{
|
||||
public static String enc(String xiVal)
|
||||
{
|
||||
try
|
||||
{
|
||||
return URLEncoder.encode(xiVal, "UTF-8");
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
// We will never hit this
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String dec(String xiVal)
|
||||
{
|
||||
try
|
||||
{
|
||||
return URLDecoder.decode(xiVal, "UTF-8");
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
// We will never hit this
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
package org.gaecounter.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.jdo.PersistenceManager;
|
||||
import javax.jdo.Query;
|
||||
import javax.jdo.annotations.PersistenceCapable;
|
||||
import javax.jdo.annotations.Persistent;
|
||||
import javax.jdo.annotations.PrimaryKey;
|
||||
|
||||
import org.joda.time.DateTimeFieldType;
|
||||
import org.joda.time.Partial;
|
||||
import org.joda.time.Period;
|
||||
|
||||
@PersistenceCapable
|
||||
public class Counter
|
||||
{
|
||||
public Counter(Type mType, String mDate, String mFile)
|
||||
{
|
||||
this.mKey = getKey(mFile, mDate);
|
||||
this.mType = mType;
|
||||
this.mDate = mDate;
|
||||
this.mFile = mFile;
|
||||
this.mCount = 1;
|
||||
}
|
||||
|
||||
public static String getKey(String xiFile, String xiDate)
|
||||
{
|
||||
return xiFile + "_" + xiDate;
|
||||
}
|
||||
|
||||
@PrimaryKey
|
||||
@Persistent
|
||||
public String mKey;
|
||||
public enum Type
|
||||
{
|
||||
YEAR("yyyy", Period.years(1))
|
||||
{
|
||||
@Override
|
||||
public Partial getPartial(int y, int m, int d)
|
||||
{
|
||||
return new Partial(new DateTimeFieldType[]
|
||||
{DateTimeFieldType.year()},
|
||||
new int[] {y});
|
||||
}
|
||||
},
|
||||
MONTH("yyyy/MM", Period.months(1))
|
||||
{
|
||||
@Override
|
||||
public Partial getPartial(int y, int m, int d)
|
||||
{
|
||||
return new Partial(new DateTimeFieldType[]
|
||||
{DateTimeFieldType.year(),
|
||||
DateTimeFieldType.monthOfYear()},
|
||||
new int[] {y, m});
|
||||
}
|
||||
},
|
||||
DAY("yyyy/MM/dd", Period.days(1))
|
||||
{
|
||||
@Override
|
||||
public Partial getPartial(int y, int m, int d)
|
||||
{
|
||||
return new Partial(new DateTimeFieldType[]
|
||||
{DateTimeFieldType.year(),
|
||||
DateTimeFieldType.monthOfYear(),
|
||||
DateTimeFieldType.dayOfMonth()},
|
||||
new int[] {y, m, d});
|
||||
}
|
||||
};
|
||||
private final String mFormat;
|
||||
public final Period mPeriod;
|
||||
private Type (String xiF, Period xiP) {mFormat = xiF; mPeriod = xiP;}
|
||||
public Partial getPartial(int y, int m, int d) {return null;}
|
||||
public String getPartialStr(int y, int m, int d)
|
||||
{
|
||||
return getPartial(y, m, d).toString(mFormat);
|
||||
}
|
||||
}
|
||||
@Persistent
|
||||
public Type mType;
|
||||
@Persistent
|
||||
public String mDate;
|
||||
@Persistent
|
||||
public String mFile;
|
||||
@Persistent
|
||||
public Integer mCount;
|
||||
|
||||
public void incrementCount()
|
||||
{
|
||||
mCount++;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<Counter> getAllByType(Type xiType)
|
||||
{
|
||||
List<Counter> detachedList = null, list = null;
|
||||
PersistenceManager pm = PMF.get().getPersistenceManager();
|
||||
try
|
||||
{
|
||||
Query lQuery = pm.newQuery(Counter.class);;
|
||||
lQuery.setFilter("mType == mTypeParam");
|
||||
lQuery.declareParameters("String mTypeParam");
|
||||
list = (List<Counter>)lQuery.execute(xiType);
|
||||
detachedList = new ArrayList<Counter>();
|
||||
for (Counter obj : list)
|
||||
{
|
||||
detachedList.add(pm.detachCopy(obj));
|
||||
}
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
pm.close();
|
||||
}
|
||||
return detachedList;
|
||||
}
|
||||
|
||||
public static Map<String,Map<String,Integer>> getPerFilePerDateMap(List<Counter> xiList)
|
||||
{
|
||||
Map<String,Map<String,Integer>> lFileMap = new HashMap<String, Map<String,Integer>>();
|
||||
|
||||
for (Counter lCounter : xiList)
|
||||
{
|
||||
String lFile = lCounter.mFile;
|
||||
String lDateStr = lCounter.mDate;
|
||||
Integer lCount = lCounter.mCount;
|
||||
|
||||
Map<String, Integer> lDateMap = lFileMap.get(lFile);
|
||||
if (lDateMap == null)
|
||||
{
|
||||
lDateMap = new HashMap<String, Integer>();
|
||||
lFileMap.put(lFile, lDateMap);
|
||||
}
|
||||
|
||||
lDateMap.put(lDateStr, lCount);
|
||||
}
|
||||
|
||||
return lFileMap;
|
||||
}
|
||||
|
||||
public static List<String> getDateStrs(Type xiType,
|
||||
Partial xiStart,
|
||||
Set<String> xiDataDateStrs)
|
||||
{
|
||||
List<String> lDateStrs = new ArrayList<String>();
|
||||
|
||||
if (xiDataDateStrs.size() > 0)
|
||||
{
|
||||
List<String> lInDataStrsList = new ArrayList<String>(xiDataDateStrs);
|
||||
Collections.sort(lInDataStrsList);
|
||||
String lOldestDate = lInDataStrsList.get(0);
|
||||
|
||||
Partial lDate = xiStart;
|
||||
String lDateStr = lDate.toString(xiType.mFormat);
|
||||
|
||||
while (lDateStr.compareTo(lOldestDate) >= 0)
|
||||
{
|
||||
lDateStrs.add(lDateStr);
|
||||
lDate = lDate.minus(xiType.mPeriod);
|
||||
lDateStr = lDate.toString(xiType.mFormat);
|
||||
}
|
||||
lDateStrs.add(lDateStr);
|
||||
|
||||
Collections.reverse(lDateStrs);
|
||||
}
|
||||
return lDateStrs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package org.gaecounter.data;
|
||||
|
||||
import javax.jdo.JDOHelper;
|
||||
import javax.jdo.PersistenceManagerFactory;
|
||||
|
||||
public final class PMF
|
||||
{
|
||||
private static final PersistenceManagerFactory pmfInstance = JDOHelper
|
||||
.getPersistenceManagerFactory("transactions-optional");
|
||||
|
||||
private PMF() { }
|
||||
|
||||
public static PersistenceManagerFactory get()
|
||||
{
|
||||
return pmfInstance;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package org.gaecounter;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gaecounter.data.Counter;
|
||||
import org.gaecounter.data.Counter.Type;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CounterTest
|
||||
{
|
||||
@Test
|
||||
public void testMapping()
|
||||
{
|
||||
List<Counter> lTestData = new ArrayList<Counter>();
|
||||
lTestData.add(new Counter(Type.DAY,
|
||||
Type.DAY.getPartialStr(2010, 1, 1),
|
||||
"test.wav"));
|
||||
lTestData.add(new Counter(Type.DAY,
|
||||
Type.DAY.getPartialStr(2011, 2, 2),
|
||||
"test.wav"));
|
||||
lTestData.add(new Counter(Type.DAY,
|
||||
Type.DAY.getPartialStr(2011, 2, 2),
|
||||
"foo.wav"));
|
||||
|
||||
Map<String, Map<String, Integer>> map = Counter.getPerFilePerDateMap(lTestData);
|
||||
assertEquals(2, map.keySet().size());
|
||||
assertTrue(map.keySet().toString(), map.keySet().contains("test.wav"));
|
||||
assertTrue(map.keySet().toString(), map.keySet().contains("foo.wav"));
|
||||
Map<String, Integer> lData = map.get("test.wav");
|
||||
assertEquals(2, lData.keySet().size());
|
||||
assertTrue(lData.keySet().toString(), lData.keySet().contains("2010/01/01"));
|
||||
assertTrue(lData.keySet().toString(), lData.keySet().contains("2011/02/02"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateStrs()
|
||||
{
|
||||
Type t = Type.DAY;
|
||||
Set<String> lDateStrs = new HashSet<String>();
|
||||
lDateStrs.add(t.getPartialStr(2010, 12, 18));
|
||||
lDateStrs.add(t.getPartialStr(2010, 12, 16));
|
||||
|
||||
List<String> dateStrs = Counter.getDateStrs(Type.DAY, Type.DAY.getPartial(2010, 12, 20), lDateStrs);
|
||||
assertEquals(6, dateStrs.size());
|
||||
assertEquals("2010/12/15", dateStrs.get(0));
|
||||
assertEquals("2010/12/16", dateStrs.get(1));
|
||||
assertEquals("2010/12/17", dateStrs.get(2));
|
||||
assertEquals("2010/12/18", dateStrs.get(3));
|
||||
assertEquals("2010/12/19", dateStrs.get(4));
|
||||
assertEquals("2010/12/20", dateStrs.get(5));
|
||||
}
|
||||
}
|
||||
|
|
@ -9,9 +9,14 @@
|
|||
</system-properties>
|
||||
|
||||
<static-files>
|
||||
<include path="/**.html" />
|
||||
<include path="/**.jar" />
|
||||
<include path="/**.xml" />
|
||||
</static-files>
|
||||
<include path="/**.html" />
|
||||
<include path="/**.xml" />
|
||||
<exclude path="/plugins/**" />
|
||||
<exclude path="/files/**" />
|
||||
</static-files>
|
||||
|
||||
<admin-console>
|
||||
<page name="Downloads" url="/downloads.jsp" />
|
||||
</admin-console>
|
||||
|
||||
</appengine-web-app>
|
||||
Binary file not shown.
|
|
@ -4,6 +4,28 @@ xmlns="http://java.sun.com/xml/ns/javaee"
|
|||
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
|
||||
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
|
||||
|
||||
<filter>
|
||||
<filter-name>CountDownloadsFilter</filter-name>
|
||||
<filter-class>org.gaecounter.CountDownloadsFilter</filter-class>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>CountDownloadsFilter</filter-name>
|
||||
<url-pattern>/plugins/*</url-pattern>
|
||||
<url-pattern>/files/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>Action</servlet-name>
|
||||
<servlet-class>org.gaecounter.ActionServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Action</servlet-name>
|
||||
<url-pattern>/action</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.html</welcome-file>
|
||||
</welcome-file-list>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,161 @@
|
|||
<%@ page import="javax.jdo.PersistenceManager" %>
|
||||
<%@ page import="javax.jdo.Query" %>
|
||||
<%@ page import="org.gaecounter.data.Counter" %>
|
||||
<%@ page import="org.gaecounter.data.Counter.Type" %>
|
||||
<%@ page import="org.gaecounter.data.PMF" %>
|
||||
<%@ page import="org.gaecounter.Utils" %>
|
||||
<%@ page import="java.util.List" %>
|
||||
<%@ page import="java.util.ArrayList" %>
|
||||
<%@ page import="java.util.Iterator" %>
|
||||
<%@ page import="java.util.Map" %>
|
||||
<%@ page import="java.util.Map.Entry" %>
|
||||
<%@ page import="java.util.HashMap" %>
|
||||
<%@ page import="java.util.Collections" %>
|
||||
<%@ page import="java.util.Set" %>
|
||||
<%@ page import="java.util.HashSet" %>
|
||||
<%@ page import="org.joda.time.DateTime" %>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Downloads</title>
|
||||
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
|
||||
<script type="text/javascript">
|
||||
google.load('visualization', '1', {packages: ['corechart']});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<%
|
||||
// Set type
|
||||
Type lType = Type.DAY;
|
||||
|
||||
// Check type
|
||||
String lModeStr = request.getParameter("mode");
|
||||
if ("month".equals(lModeStr))
|
||||
{
|
||||
lType = Type.MONTH;
|
||||
}
|
||||
else if ("year".equals(lModeStr))
|
||||
{
|
||||
lType = Type.YEAR;
|
||||
}
|
||||
|
||||
// Fetch data
|
||||
List<Counter> lRecords = Counter.getAllByType(lType);
|
||||
|
||||
// Filename -> DateStr -> Count
|
||||
Map<String,Map<String,Integer>> lPerDateStrDownloads = Counter.getPerFilePerDateMap(lRecords);
|
||||
|
||||
// Date strings
|
||||
Set<String> dateStrsSet = new HashSet<String>();
|
||||
for (String file : lPerDateStrDownloads.keySet())
|
||||
{
|
||||
dateStrsSet.addAll(lPerDateStrDownloads.get(file).keySet());
|
||||
}
|
||||
DateTime lNow = new DateTime();
|
||||
List<String> dateStrs = Counter.getDateStrs(lType,
|
||||
lType.getPartial(lNow.getYear(), lNow.getMonthOfYear(), lNow.getDayOfMonth()),
|
||||
dateStrsSet);
|
||||
%>
|
||||
<script type="text/javascript">
|
||||
function drawVisualization() {
|
||||
// Raw data
|
||||
var filenames =
|
||||
[<%Iterator<String> lFiles = lPerDateStrDownloads.keySet().iterator(); while (lFiles.hasNext()) {%>
|
||||
'<%=lFiles.next()%>'<%=(lFiles.hasNext() ? "," : "")%>
|
||||
<%}%>];
|
||||
var datestrs =
|
||||
[<%Iterator<String> dateStrsIter = dateStrs.iterator(); while (dateStrsIter.hasNext()) {%>
|
||||
'<%=dateStrsIter.next()%>'<%=(dateStrsIter.hasNext() ? "," : "")%>
|
||||
<%}%>];
|
||||
var downloadsByFile =
|
||||
[
|
||||
<%Iterator<Entry<String,Map<String,Integer>>> iter = lPerDateStrDownloads.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Entry<String,Map<String,Integer>> entry = iter.next();
|
||||
Map<String,Integer> perDateCount = entry.getValue();
|
||||
dateStrsIter = dateStrs.iterator();%>
|
||||
[
|
||||
<%while(dateStrsIter.hasNext()) {
|
||||
String dateStr = dateStrsIter.next();
|
||||
Integer lVal = perDateCount.get(dateStr);
|
||||
if (lVal == null) lVal = 0;%>
|
||||
<%=lVal%><%=(dateStrsIter.hasNext() ? "," : "")%>
|
||||
<%}%>
|
||||
]<%=(iter.hasNext() ? "," : "")%> // <%=entry.getKey()%>
|
||||
<%}%>
|
||||
];
|
||||
|
||||
// Create and populate the data table.
|
||||
var data = new google.visualization.DataTable();
|
||||
|
||||
// Prepare columns
|
||||
data.addColumn('string', 'Date');
|
||||
for (var i = 0; i < filenames.length; ++i) {
|
||||
data.addColumn('number', filenames[i]);
|
||||
}
|
||||
|
||||
// Fill in datestr strings
|
||||
data.addRows(datestrs.length);
|
||||
for (var i = 0; i < datestrs.length; ++i) {
|
||||
data.setCell(i, 0, datestrs[i]);
|
||||
}
|
||||
|
||||
// Fill in download data
|
||||
for (var i = 0; i < filenames.length; ++i) {
|
||||
var downloads = downloadsByFile[i];
|
||||
for (var datestr = 0; datestr < datestrs.length; ++datestr) {
|
||||
data.setCell(datestr, i + 1, downloads[datestr]);
|
||||
}
|
||||
}
|
||||
|
||||
// Create and draw the visualization.
|
||||
var ac = new google.visualization.AreaChart(document.getElementById('visualization'));
|
||||
ac.draw(data, {
|
||||
title : 'Downloads by Date',
|
||||
isStacked: true,
|
||||
//width: 600,
|
||||
height: 400,
|
||||
vAxis: {title: "Downloads"},
|
||||
hAxis: {title: "Date"}
|
||||
});
|
||||
}
|
||||
|
||||
google.setOnLoadCallback(drawVisualization);
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function doClearFile(fileName)
|
||||
{ window.location.href = "action?action=clearfile&file=" + fileName + "&redir=downloads.jsp"; }
|
||||
|
||||
function doClear()
|
||||
{ window.location.href = "action?action=clear&redir=downloads.jsp"; }
|
||||
|
||||
function doTestData()
|
||||
{ window.location.href = "action?action=testdata&redir=downloads.jsp"; }
|
||||
|
||||
function setMode(mode)
|
||||
{ window.location.href = "downloads.jsp?mode=" + mode; }
|
||||
</script>
|
||||
<input type="submit" value="Year" onclick="setMode('year')" />
|
||||
<input type="submit" value="Month" onclick="setMode('month')" />
|
||||
<input type="submit" value="Day" onclick="setMode('day')" /><br>
|
||||
<div style="width: 100%;" id="visualization"></div>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Filename</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<%
|
||||
for (Entry<String,Map<String,Integer>> entry : lPerDateStrDownloads.entrySet()) {
|
||||
%>
|
||||
<tr>
|
||||
<td><%=entry.getKey()%></td>
|
||||
<td><input type="submit" value="Clear File" onclick="doClearFile('<%=Utils.enc(entry.getKey())%>')" /></td>
|
||||
</tr>
|
||||
<% } %>
|
||||
</table><br>
|
||||
<input type="submit" value="Clear All Data (<%=lPerDateStrDownloads.keySet().size()%> Files)" onclick="doClear()" />
|
||||
<br><br><br>
|
||||
<input type="submit" value="Create Test Data" onclick="doTestData()" />
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,65 @@
|
|||
<!--
|
||||
You are free to copy and use this sample in accordance with the terms of the
|
||||
Apache license (http://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
-->
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
|
||||
<title>
|
||||
Google Visualization API Sample
|
||||
</title>
|
||||
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
|
||||
<script type="text/javascript">
|
||||
google.load('visualization', '1', {packages: ['corechart']});
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
function drawVisualization() {
|
||||
// Some raw data (not necessarily accurate)
|
||||
var countries =
|
||||
['Bolivia', 'Ecuador',
|
||||
'Madagascar', 'Papua Guinea', 'Rwanda'];
|
||||
var months = ['2004/05', '2005/06', '2006/07', '2007/08', '2008/09'];
|
||||
var productionByCountry = [[165, 135, 157, 139, 136],
|
||||
[938, 1120, 1167, 1110, 691],
|
||||
[522, 599, 587, 615, 629],
|
||||
[998, 1268, 807, 968, 1026],
|
||||
[450, 288, 397, 215, 366]];
|
||||
|
||||
// Create and populate the data table.
|
||||
var data = new google.visualization.DataTable();
|
||||
data.addColumn('string', 'Month');
|
||||
for (var i = 0; i < countries.length; ++i) {
|
||||
data.addColumn('number', countries[i]);
|
||||
}
|
||||
data.addRows(months.length);
|
||||
for (var i = 0; i < months.length; ++i) {
|
||||
data.setCell(i, 0, months[i]);
|
||||
}
|
||||
for (var i = 0; i < countries.length; ++i) {
|
||||
var country = productionByCountry[i];
|
||||
for (var month = 0; month < months.length; ++month) {
|
||||
data.setCell(month, i + 1, country[month]);
|
||||
}
|
||||
}
|
||||
// Create and draw the visualization.
|
||||
var ac = new google.visualization.AreaChart(document.getElementById('visualization'));
|
||||
ac.draw(data, {
|
||||
title : 'Monthly Coffee Production by Country',
|
||||
isStacked: true,
|
||||
width: 600,
|
||||
height: 400,
|
||||
vAxis: {title: "Cups"},
|
||||
hAxis: {title: "Month"}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
google.setOnLoadCallback(drawVisualization);
|
||||
</script>
|
||||
</head>
|
||||
<body style="font-family: Arial;border: 0 none;">
|
||||
<div id="visualization" style="width: 600px; height: 400px;"></div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue