diff src/nabble/model/DailyNumber.java @ 0:7ecd1a4ef557

add content
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 21 Mar 2019 19:15:52 -0600
parents
children 72765b66e2c3
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/nabble/model/DailyNumber.java	Thu Mar 21 19:15:52 2019 -0600
@@ -0,0 +1,219 @@
+package nabble.model;
+
+import fschmidt.db.Listener;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+
+public final class DailyNumber {
+	private static final long updateFreq = 1000L*60;
+	private static long lastUpdate = System.currentTimeMillis();
+	private static final Object lock = new Object();
+	private static final List<DailyNumber> dailyNumbers = new ArrayList<DailyNumber>();
+	private static boolean hasChanged = false;
+
+	private final String field;
+	private int inc = 0;
+
+	private DailyNumber(String field) {
+		this.field = field;
+		synchronized(lock) {
+			dailyNumbers.add(this);
+		}
+	}
+
+	public void inc() {
+		synchronized(lock) {
+			hasChanged = true;
+			inc++;
+			if( System.currentTimeMillis() - lastUpdate >= updateFreq )
+				doSave();
+		}
+	}
+
+	public void dec() {
+		synchronized(lock) {
+			hasChanged = true;
+			inc--;
+			if( System.currentTimeMillis() - lastUpdate >= updateFreq )
+				doSave();
+		}
+	}
+
+	static void shutdown() {
+		synchronized(lock) {
+			doSave();
+		}
+	}
+
+	private static void doSave() {
+		if( !hasChanged )
+			return;
+		hasChanged = false;
+		try {
+			Connection con = Db.dbGlobal().getConnection();
+			try {
+				boolean hasInc = false;
+				StringBuilder buf = new StringBuilder();
+				buf.append( "update daily_numbers" );
+				for( DailyNumber dn : dailyNumbers ) {
+					if( dn.inc == 0 )
+						continue;
+					if( !hasInc ) {
+						buf.append( " set " );
+						hasInc = true;
+					} else {
+						buf.append( ", " );
+					}
+					buf.append( dn.field ).append( "=" )
+						.append( dn.field ).append( "+" ).append( dn.inc );
+					dn.inc = 0;
+				}
+				if( !hasInc )
+					return;
+				java.sql.Date day = new java.sql.Date(lastUpdate);
+				buf.append( " where day=cast(" ).append( Db.dbGlobal().arcana().quote(day) ).append(" as date)");
+				Statement stmt = con.createStatement();
+				int n = stmt.executeUpdate( buf.toString() );
+				if( n == 0 ) {
+					stmt.executeUpdate(
+						"insert into daily_numbers (day) values (" + Db.dbGlobal().arcana().quote(day) + ")"
+					);
+					if( stmt.executeUpdate(buf.toString()) != 1 )
+						throw new RuntimeException();
+				}
+				stmt.close();
+			} finally {
+				con.close();
+			}
+		} catch(SQLException e) {
+			throw new RuntimeException(e);
+		} finally {
+			lastUpdate = System.currentTimeMillis();
+		}
+	}
+
+	private static ThreadLocal<java.sql.Date> tlDay = new ThreadLocal<java.sql.Date>();
+	private static ThreadLocal<Map<DailyNumber,Integer>> tlMap = new ThreadLocal<Map<DailyNumber,Integer>>();
+
+	public int get(Date date) {
+		java.sql.Date day = new java.sql.Date(date.getTime());
+		if( !day.equals(tlDay.get()) ) {
+			Map<DailyNumber,Integer> map = new HashMap<DailyNumber,Integer>();
+			try {
+				Connection con = Db.dbGlobal().getConnection();
+				PreparedStatement stmt = con.prepareStatement(
+					"select * from daily_numbers where day=?"
+				);
+				stmt.setDate(1,day);
+				ResultSet rs = stmt.executeQuery();
+				boolean hasNumbers = rs.next();
+				for( Iterator i=dailyNumbers.iterator(); i.hasNext(); ) {
+					DailyNumber dn = (DailyNumber)i.next();
+					map.put( dn, new Integer(hasNumbers?rs.getInt(dn.field):0) );
+				}
+				stmt.close();
+				con.close();
+			} catch(SQLException e) {
+				throw new RuntimeException(e);
+			}
+			tlDay.set(day);
+			tlMap.set(map);
+		}
+		Map<DailyNumber,Integer> map = tlMap.get();
+		return map.get(this);
+	}
+
+	public static final DailyNumber totalVisits = new DailyNumber("total_visits");
+	public static final DailyNumber directVisits = new DailyNumber("direct_visits");
+	public static final DailyNumber searchEngineVisits = new DailyNumber("se_visits");
+	public static final DailyNumber externalVisits = new DailyNumber("ext_visits");
+	public static final DailyNumber adVisits = new DailyNumber("ad_visits");
+	public static final DailyNumber registrations = new DailyNumber("registrations");
+	public static final DailyNumber logins = new DailyNumber("logins");
+	public static final DailyNumber externalPosts = new DailyNumber("external_posts");
+	public static final DailyNumber internalPosts = new DailyNumber("internal_posts");
+	public static final DailyNumber replies = new DailyNumber("replies");
+	public static final DailyNumber localForumPosts = new DailyNumber("local_forum_posts");
+
+	public static final DailyNumber forumsStarted = new DailyNumber("forums_started");
+	public static final DailyNumber galleriesStarted = new DailyNumber("galleries_started");
+	public static final DailyNumber newspapersStarted = new DailyNumber("newspapers_started");
+	public static final DailyNumber blogsStarted = new DailyNumber("blogs_started");
+
+	public static final DailyNumber firstForumPosts = new DailyNumber("first_forum_posts");
+	public static final DailyNumber firstGalleryPosts = new DailyNumber("first_gallery_posts");
+	public static final DailyNumber firstBlogPosts = new DailyNumber("first_blog_posts");
+	public static final DailyNumber firstNewspaperPosts = new DailyNumber("first_newspaper_posts");
+
+	public static final DailyNumber blockedSpams = new DailyNumber("blocked_spams");
+	public static final DailyNumber tweaks = new DailyNumber("tweaks");
+
+
+	static {
+		NodeImpl.addPostInsertListener(new Listener<NodeImpl>(){
+			public void event(final NodeImpl n) {
+				if( ModelHome.insideImportProcedure.get() )
+					return;
+				Db.dbGlobal().runAfterCommit(new Runnable(){public void run(){
+					NodeImpl node = (NodeImpl)n.getGoodCopy();
+					if( node.getKind()==Node.Kind.APP ) {
+						Node parent = node.getParent();
+						if( parent==null || !parent.getOwner().equals(node.getOwner()) ) {
+							String type = node.getType();
+							if (type.equals(Node.Type.GALLERY))
+								DailyNumber.galleriesStarted.inc();
+							else if (type.equals(Node.Type.NEWS))
+								DailyNumber.newspapersStarted.inc();
+							else if (type.equals(Node.Type.BLOG))
+								DailyNumber.blogsStarted.inc();
+							else
+								DailyNumber.forumsStarted.inc();
+						}
+						return;
+					}
+					NodeImpl post = node;
+					if( post.isFromMailingList() ) {
+						DailyNumber.externalPosts.inc();
+					} else {
+						DailyNumber.internalPosts.inc();
+						if( post.getAssociatedMailingList() == null )
+							DailyNumber.localForumPosts.inc();
+					}
+					NodeImpl parent = post.getParentImpl();
+					if( parent != null && parent.getKind()==Node.Kind.POST && !parent.isFromMailingList() )
+						DailyNumber.replies.inc();
+
+					boolean isFirstPost = parent != null && parent.getKind()==Node.Kind.APP && parent.getDescendantCount() == 1;
+					if (isFirstPost) {
+						String type = parent.getType();
+						if (type.equals(Node.Type.GALLERY))
+							DailyNumber.firstGalleryPosts.inc();
+						else if (type.equals(Node.Type.NEWS))
+							DailyNumber.firstNewspaperPosts.inc();
+						else if (type.equals(Node.Type.BLOG))
+							DailyNumber.firstBlogPosts.inc();
+						else
+							DailyNumber.firstForumPosts.inc();
+					}
+				}});
+			}
+		});
+	}
+
+	static void nop() {}
+
+	static {
+		Init.dailyNumberStarted = true;
+	}
+}