0
|
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 }
|