diff --git a/.gitignore b/.gitignore index 79af0f6..249c1ca 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,6 @@ asm3.2_* asm_patch* libsrc* *private* -*genfile* \ No newline at end of file +*genfile* +classes/ +appengine-generated/ \ No newline at end of file diff --git a/intrace.appengine/.classpath b/intrace.appengine/.classpath index 9a9cdee..37202b8 100644 --- a/intrace.appengine/.classpath +++ b/intrace.appengine/.classpath @@ -3,5 +3,8 @@ + + + diff --git a/intrace.appengine/.settings/com.google.appengine.eclipse.core.prefs b/intrace.appengine/.settings/com.google.appengine.eclipse.core.prefs index 1427f4f..04c4075 100644 --- a/intrace.appengine/.settings/com.google.appengine.eclipse.core.prefs +++ b/intrace.appengine/.settings/com.google.appengine.eclipse.core.prefs @@ -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= diff --git a/intrace.appengine/lib/junit-4.10.jar b/intrace.appengine/lib/junit-4.10.jar new file mode 100644 index 0000000..bf5c0b9 Binary files /dev/null and b/intrace.appengine/lib/junit-4.10.jar differ diff --git a/intrace.appengine/src/org/gaecounter/ActionServlet.java b/intrace.appengine/src/org/gaecounter/ActionServlet.java new file mode 100644 index 0000000..8ef68d1 --- /dev/null +++ b/intrace.appengine/src/org/gaecounter/ActionServlet.java @@ -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); + } +} diff --git a/intrace.appengine/src/org/gaecounter/CountDownloadsFilter.java b/intrace.appengine/src/org/gaecounter/CountDownloadsFilter.java new file mode 100644 index 0000000..d4de20a --- /dev/null +++ b/intrace.appengine/src/org/gaecounter/CountDownloadsFilter.java @@ -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 + } +} diff --git a/intrace.appengine/src/org/gaecounter/Utils.java b/intrace.appengine/src/org/gaecounter/Utils.java new file mode 100644 index 0000000..28a73f0 --- /dev/null +++ b/intrace.appengine/src/org/gaecounter/Utils.java @@ -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; + } + } +} diff --git a/intrace.appengine/src/org/gaecounter/data/Counter.java b/intrace.appengine/src/org/gaecounter/data/Counter.java new file mode 100644 index 0000000..515afc1 --- /dev/null +++ b/intrace.appengine/src/org/gaecounter/data/Counter.java @@ -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 getAllByType(Type xiType) + { + List 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)lQuery.execute(xiType); + detachedList = new ArrayList(); + for (Counter obj : list) + { + detachedList.add(pm.detachCopy(obj)); + } + + } + finally + { + pm.close(); + } + return detachedList; + } + + public static Map> getPerFilePerDateMap(List xiList) + { + Map> lFileMap = new HashMap>(); + + for (Counter lCounter : xiList) + { + String lFile = lCounter.mFile; + String lDateStr = lCounter.mDate; + Integer lCount = lCounter.mCount; + + Map lDateMap = lFileMap.get(lFile); + if (lDateMap == null) + { + lDateMap = new HashMap(); + lFileMap.put(lFile, lDateMap); + } + + lDateMap.put(lDateStr, lCount); + } + + return lFileMap; + } + + public static List getDateStrs(Type xiType, + Partial xiStart, + Set xiDataDateStrs) + { + List lDateStrs = new ArrayList(); + + if (xiDataDateStrs.size() > 0) + { + List lInDataStrsList = new ArrayList(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; + } + +} diff --git a/intrace.appengine/src/org/gaecounter/data/PMF.java b/intrace.appengine/src/org/gaecounter/data/PMF.java new file mode 100644 index 0000000..9793723 --- /dev/null +++ b/intrace.appengine/src/org/gaecounter/data/PMF.java @@ -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; + } +} \ No newline at end of file diff --git a/intrace.appengine/testsrc/org/gaecounter/CounterTest.java b/intrace.appengine/testsrc/org/gaecounter/CounterTest.java new file mode 100644 index 0000000..ac777ef --- /dev/null +++ b/intrace.appengine/testsrc/org/gaecounter/CounterTest.java @@ -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 lTestData = new ArrayList(); + 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> 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 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 lDateStrs = new HashSet(); + lDateStrs.add(t.getPartialStr(2010, 12, 18)); + lDateStrs.add(t.getPartialStr(2010, 12, 16)); + + List 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)); + } +} diff --git a/intrace.appengine/war/WEB-INF/appengine-web.xml b/intrace.appengine/war/WEB-INF/appengine-web.xml index 0dbde18..766ffc7 100644 --- a/intrace.appengine/war/WEB-INF/appengine-web.xml +++ b/intrace.appengine/war/WEB-INF/appengine-web.xml @@ -9,9 +9,14 @@ - - - - + + + + + + + + + \ No newline at end of file diff --git a/intrace.appengine/war/WEB-INF/lib/joda-time-2.0.jar b/intrace.appengine/war/WEB-INF/lib/joda-time-2.0.jar new file mode 100644 index 0000000..169a7a4 Binary files /dev/null and b/intrace.appengine/war/WEB-INF/lib/joda-time-2.0.jar differ diff --git a/intrace.appengine/war/WEB-INF/web.xml b/intrace.appengine/war/WEB-INF/web.xml index 5755f49..27ef3d9 100644 --- a/intrace.appengine/war/WEB-INF/web.xml +++ b/intrace.appengine/war/WEB-INF/web.xml @@ -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"> + + + CountDownloadsFilter + org.gaecounter.CountDownloadsFilter + + + + CountDownloadsFilter + /plugins/* + /files/* + + + + Action + org.gaecounter.ActionServlet + + + + Action + /action + + index.html diff --git a/intrace.appengine/war/downloads.jsp b/intrace.appengine/war/downloads.jsp new file mode 100644 index 0000000..be2ca54 --- /dev/null +++ b/intrace.appengine/war/downloads.jsp @@ -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" %> + + + + Downloads + + + + + <% + // 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 lRecords = Counter.getAllByType(lType); + + // Filename -> DateStr -> Count + Map> lPerDateStrDownloads = Counter.getPerFilePerDateMap(lRecords); + + // Date strings + Set dateStrsSet = new HashSet(); + for (String file : lPerDateStrDownloads.keySet()) + { + dateStrsSet.addAll(lPerDateStrDownloads.get(file).keySet()); + } + DateTime lNow = new DateTime(); + List dateStrs = Counter.getDateStrs(lType, + lType.getPartial(lNow.getYear(), lNow.getMonthOfYear(), lNow.getDayOfMonth()), + dateStrsSet); + %> + + + + + +
+
+ + + + + + <% + for (Entry> entry : lPerDateStrDownloads.entrySet()) { + %> + + + + + <% } %> +
Filename
<%=entry.getKey()%>

+ +


+ + + \ No newline at end of file diff --git a/intrace.appengine/war/files/JTDA.app.tar b/intrace.appengine/war/files/JTDA.app.tar new file mode 100644 index 0000000..b583785 Binary files /dev/null and b/intrace.appengine/war/files/JTDA.app.tar differ diff --git a/intrace.appengine/war/files/emmacheck-0.2.jar b/intrace.appengine/war/files/emmacheck-0.2.jar new file mode 100644 index 0000000..504e3c4 Binary files /dev/null and b/intrace.appengine/war/files/emmacheck-0.2.jar differ diff --git a/intrace.appengine/war/files/inmemprofiler.dll b/intrace.appengine/war/files/inmemprofiler.dll new file mode 100644 index 0000000..3e01f00 Binary files /dev/null and b/intrace.appengine/war/files/inmemprofiler.dll differ diff --git a/intrace.appengine/war/files/inmemprofiler.jar b/intrace.appengine/war/files/inmemprofiler.jar new file mode 100644 index 0000000..c13dd0d Binary files /dev/null and b/intrace.appengine/war/files/inmemprofiler.jar differ diff --git a/intrace.appengine/war/files/intrace-agent.jar b/intrace.appengine/war/files/intrace-agent.jar new file mode 100644 index 0000000..cd3b3e5 Binary files /dev/null and b/intrace.appengine/war/files/intrace-agent.jar differ diff --git a/intrace.appengine/war/files/intrace-ui.jar b/intrace.appengine/war/files/intrace-ui.jar new file mode 100644 index 0000000..a0ab0d2 Binary files /dev/null and b/intrace.appengine/war/files/intrace-ui.jar differ diff --git a/intrace.appengine/war/files/jtda.jar b/intrace.appengine/war/files/jtda.jar new file mode 100644 index 0000000..f25b6ca Binary files /dev/null and b/intrace.appengine/war/files/jtda.jar differ diff --git a/intrace.appengine/war/files/libinmemprofiler.so b/intrace.appengine/war/files/libinmemprofiler.so new file mode 100644 index 0000000..e9b17e1 Binary files /dev/null and b/intrace.appengine/war/files/libinmemprofiler.so differ diff --git a/intrace.appengine/war/files/swtjar.jar b/intrace.appengine/war/files/swtjar.jar new file mode 100644 index 0000000..67a330e Binary files /dev/null and b/intrace.appengine/war/files/swtjar.jar differ diff --git a/intrace.appengine/war/stats.html b/intrace.appengine/war/stats.html new file mode 100644 index 0000000..2c2696c --- /dev/null +++ b/intrace.appengine/war/stats.html @@ -0,0 +1,65 @@ + + + + + + + + Google Visualization API Sample + + + + + + +
+ + \ No newline at end of file