comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:7ecd1a4ef557
1 package nabble.model;
2
3 import fschmidt.db.Listener;
4
5 import java.sql.Connection;
6 import java.sql.PreparedStatement;
7 import java.sql.ResultSet;
8 import java.sql.SQLException;
9 import java.sql.Statement;
10 import java.util.ArrayList;
11 import java.util.Date;
12 import java.util.HashMap;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Map;
16
17
18 public final class DailyNumber {
19 private static final long updateFreq = 1000L*60;
20 private static long lastUpdate = System.currentTimeMillis();
21 private static final Object lock = new Object();
22 private static final List<DailyNumber> dailyNumbers = new ArrayList<DailyNumber>();
23 private static boolean hasChanged = false;
24
25 private final String field;
26 private int inc = 0;
27
28 private DailyNumber(String field) {
29 this.field = field;
30 synchronized(lock) {
31 dailyNumbers.add(this);
32 }
33 }
34
35 public void inc() {
36 synchronized(lock) {
37 hasChanged = true;
38 inc++;
39 if( System.currentTimeMillis() - lastUpdate >= updateFreq )
40 doSave();
41 }
42 }
43
44 public void dec() {
45 synchronized(lock) {
46 hasChanged = true;
47 inc--;
48 if( System.currentTimeMillis() - lastUpdate >= updateFreq )
49 doSave();
50 }
51 }
52
53 static void shutdown() {
54 synchronized(lock) {
55 doSave();
56 }
57 }
58
59 private static void doSave() {
60 if( !hasChanged )
61 return;
62 hasChanged = false;
63 try {
64 Connection con = Db.dbGlobal().getConnection();
65 try {
66 boolean hasInc = false;
67 StringBuilder buf = new StringBuilder();
68 buf.append( "update daily_numbers" );
69 for( DailyNumber dn : dailyNumbers ) {
70 if( dn.inc == 0 )
71 continue;
72 if( !hasInc ) {
73 buf.append( " set " );
74 hasInc = true;
75 } else {
76 buf.append( ", " );
77 }
78 buf.append( dn.field ).append( "=" )
79 .append( dn.field ).append( "+" ).append( dn.inc );
80 dn.inc = 0;
81 }
82 if( !hasInc )
83 return;
84 java.sql.Date day = new java.sql.Date(lastUpdate);
85 buf.append( " where day=cast(" ).append( Db.dbGlobal().arcana().quote(day) ).append(" as date)");
86 Statement stmt = con.createStatement();
87 int n = stmt.executeUpdate( buf.toString() );
88 if( n == 0 ) {
89 stmt.executeUpdate(
90 "insert into daily_numbers (day) values (" + Db.dbGlobal().arcana().quote(day) + ")"
91 );
92 if( stmt.executeUpdate(buf.toString()) != 1 )
93 throw new RuntimeException();
94 }
95 stmt.close();
96 } finally {
97 con.close();
98 }
99 } catch(SQLException e) {
100 throw new RuntimeException(e);
101 } finally {
102 lastUpdate = System.currentTimeMillis();
103 }
104 }
105
106 private static ThreadLocal<java.sql.Date> tlDay = new ThreadLocal<java.sql.Date>();
107 private static ThreadLocal<Map<DailyNumber,Integer>> tlMap = new ThreadLocal<Map<DailyNumber,Integer>>();
108
109 public int get(Date date) {
110 java.sql.Date day = new java.sql.Date(date.getTime());
111 if( !day.equals(tlDay.get()) ) {
112 Map<DailyNumber,Integer> map = new HashMap<DailyNumber,Integer>();
113 try {
114 Connection con = Db.dbGlobal().getConnection();
115 PreparedStatement stmt = con.prepareStatement(
116 "select * from daily_numbers where day=?"
117 );
118 stmt.setDate(1,day);
119 ResultSet rs = stmt.executeQuery();
120 boolean hasNumbers = rs.next();
121 for( Iterator i=dailyNumbers.iterator(); i.hasNext(); ) {
122 DailyNumber dn = (DailyNumber)i.next();
123 map.put( dn, new Integer(hasNumbers?rs.getInt(dn.field):0) );
124 }
125 stmt.close();
126 con.close();
127 } catch(SQLException e) {
128 throw new RuntimeException(e);
129 }
130 tlDay.set(day);
131 tlMap.set(map);
132 }
133 Map<DailyNumber,Integer> map = tlMap.get();
134 return map.get(this);
135 }
136
137 public static final DailyNumber totalVisits = new DailyNumber("total_visits");
138 public static final DailyNumber directVisits = new DailyNumber("direct_visits");
139 public static final DailyNumber searchEngineVisits = new DailyNumber("se_visits");
140 public static final DailyNumber externalVisits = new DailyNumber("ext_visits");
141 public static final DailyNumber adVisits = new DailyNumber("ad_visits");
142 public static final DailyNumber registrations = new DailyNumber("registrations");
143 public static final DailyNumber logins = new DailyNumber("logins");
144 public static final DailyNumber externalPosts = new DailyNumber("external_posts");
145 public static final DailyNumber internalPosts = new DailyNumber("internal_posts");
146 public static final DailyNumber replies = new DailyNumber("replies");
147 public static final DailyNumber localForumPosts = new DailyNumber("local_forum_posts");
148
149 public static final DailyNumber forumsStarted = new DailyNumber("forums_started");
150 public static final DailyNumber galleriesStarted = new DailyNumber("galleries_started");
151 public static final DailyNumber newspapersStarted = new DailyNumber("newspapers_started");
152 public static final DailyNumber blogsStarted = new DailyNumber("blogs_started");
153
154 public static final DailyNumber firstForumPosts = new DailyNumber("first_forum_posts");
155 public static final DailyNumber firstGalleryPosts = new DailyNumber("first_gallery_posts");
156 public static final DailyNumber firstBlogPosts = new DailyNumber("first_blog_posts");
157 public static final DailyNumber firstNewspaperPosts = new DailyNumber("first_newspaper_posts");
158
159 public static final DailyNumber blockedSpams = new DailyNumber("blocked_spams");
160 public static final DailyNumber tweaks = new DailyNumber("tweaks");
161
162
163 static {
164 NodeImpl.addPostInsertListener(new Listener<NodeImpl>(){
165 public void event(final NodeImpl n) {
166 if( ModelHome.insideImportProcedure.get() )
167 return;
168 Db.dbGlobal().runAfterCommit(new Runnable(){public void run(){
169 NodeImpl node = (NodeImpl)n.getGoodCopy();
170 if( node.getKind()==Node.Kind.APP ) {
171 Node parent = node.getParent();
172 if( parent==null || !parent.getOwner().equals(node.getOwner()) ) {
173 String type = node.getType();
174 if (type.equals(Node.Type.GALLERY))
175 DailyNumber.galleriesStarted.inc();
176 else if (type.equals(Node.Type.NEWS))
177 DailyNumber.newspapersStarted.inc();
178 else if (type.equals(Node.Type.BLOG))
179 DailyNumber.blogsStarted.inc();
180 else
181 DailyNumber.forumsStarted.inc();
182 }
183 return;
184 }
185 NodeImpl post = node;
186 if( post.isFromMailingList() ) {
187 DailyNumber.externalPosts.inc();
188 } else {
189 DailyNumber.internalPosts.inc();
190 if( post.getAssociatedMailingList() == null )
191 DailyNumber.localForumPosts.inc();
192 }
193 NodeImpl parent = post.getParentImpl();
194 if( parent != null && parent.getKind()==Node.Kind.POST && !parent.isFromMailingList() )
195 DailyNumber.replies.inc();
196
197 boolean isFirstPost = parent != null && parent.getKind()==Node.Kind.APP && parent.getDescendantCount() == 1;
198 if (isFirstPost) {
199 String type = parent.getType();
200 if (type.equals(Node.Type.GALLERY))
201 DailyNumber.firstGalleryPosts.inc();
202 else if (type.equals(Node.Type.NEWS))
203 DailyNumber.firstNewspaperPosts.inc();
204 else if (type.equals(Node.Type.BLOG))
205 DailyNumber.firstBlogPosts.inc();
206 else
207 DailyNumber.firstForumPosts.inc();
208 }
209 }});
210 }
211 });
212 }
213
214 static void nop() {}
215
216 static {
217 Init.dailyNumberStarted = true;
218 }
219 }