001 package com.croftsoft.apps.chat.server;
002
003 import java.util.*;
004
005 import com.croftsoft.core.lang.NullArgumentException;
006 import com.croftsoft.core.lang.lifecycle.Commissionable;
007 import com.croftsoft.core.math.MathConstants;
008 import com.croftsoft.core.role.Server;
009 import com.croftsoft.core.security.Authentication;
010 import com.croftsoft.core.util.ClassMapServer;
011 import com.croftsoft.core.util.consumer.Consumer;
012 import com.croftsoft.core.util.loop.FixedDelayLoopGovernor;
013 import com.croftsoft.core.util.loop.Loopable;
014 import com.croftsoft.core.util.loop.Looper;
015
016 import com.croftsoft.apps.chat.ChatConstants;
017 import com.croftsoft.apps.chat.model.ChatGame;
018 import com.croftsoft.apps.chat.model.seri.SeriChatGame;
019 import com.croftsoft.apps.chat.request.CreateUserRequest;
020 import com.croftsoft.apps.chat.request.PullRequest;
021 import com.croftsoft.apps.chat.request.Request;
022 import com.croftsoft.apps.chat.response.UnknownUserResponse;
023 import com.croftsoft.apps.chat.server.CreateUserServer;
024 import com.croftsoft.apps.chat.user.User;
025 import com.croftsoft.apps.chat.user.UserStore;
026 import com.croftsoft.apps.chat.user.seri.SeriUserStore;
027
028 /*********************************************************************
029 * Chat server.
030 *
031 * @version
032 * 2003-06-18
033 * @since
034 * 2003-06-04
035 * @author
036 * <a href="http://www.CroftSoft.com/">David Wallace Croft</a>
037 *********************************************************************/
038
039 public final class ChatServer
040 implements Commissionable, Server
041 //////////////////////////////////////////////////////////////////////
042 //////////////////////////////////////////////////////////////////////
043 {
044
045 private static final boolean DEBUG = true;
046
047 private static final long SAMPLE_PERIOD
048 = 10 * MathConstants.MILLISECONDS_PER_SECOND;
049
050 private static final double UPDATE_RATE = 30.0;
051
052 //
053
054 private final UserStore userStore;
055
056 private final ChatGame chatGame;
057
058 private final Looper looper;
059
060 private final CreateUserServer createUserServer;
061
062 private final PullServer pullServer;
063
064 //
065
066 private long count;
067
068 private long startTime;
069
070 private long lastRequestTime;
071
072 //////////////////////////////////////////////////////////////////////
073 //////////////////////////////////////////////////////////////////////
074
075 public ChatServer ( )
076 //////////////////////////////////////////////////////////////////////
077 {
078 userStore = new SeriUserStore ( );
079
080 chatGame = new SeriChatGame ( userStore );
081
082 createUserServer = new CreateUserServer ( userStore );
083
084 pullServer = new PullServer ( ChatConstants.QUEUE_PULL_TIMEOUT );
085
086 looper = new Looper (
087 new Loopable ( )
088 {
089 public boolean loop ( )
090 {
091 return ChatServer.this.loop ( );
092 }
093 },
094 new FixedDelayLoopGovernor ( UPDATE_RATE ),
095 null,
096 ( String ) null,
097 Thread.MIN_PRIORITY,
098 true );
099 }
100
101 //////////////////////////////////////////////////////////////////////
102 //////////////////////////////////////////////////////////////////////
103
104 public void init ( )
105 //////////////////////////////////////////////////////////////////////
106 {
107 startTime = System.currentTimeMillis ( );
108
109 lastRequestTime = startTime;
110
111 looper.init ( );
112 }
113
114 public void destroy ( )
115 //////////////////////////////////////////////////////////////////////
116 {
117 looper.stop ( );
118
119 looper.destroy ( );
120 }
121
122 //////////////////////////////////////////////////////////////////////
123 //////////////////////////////////////////////////////////////////////
124
125 public Object serve ( Object requestObject )
126 //////////////////////////////////////////////////////////////////////
127 {
128 if ( DEBUG )
129 {
130 System.out.println ( "ChatServer.serve(" + requestObject + ")" );
131 }
132
133 synchronized ( this )
134 {
135 lastRequestTime = System.currentTimeMillis ( );
136
137 if ( DEBUG )
138 {
139 ++count;
140 }
141 }
142
143 looper.start ( );
144
145 if ( requestObject instanceof CreateUserRequest )
146 {
147 CreateUserRequest createUserRequest
148 = ( CreateUserRequest ) requestObject;
149
150 return createUserServer.serve ( createUserRequest );
151 }
152
153 if ( !( requestObject instanceof Request ) )
154 {
155 throw new IllegalArgumentException ( );
156 }
157
158 Request request = ( Request ) requestObject;
159
160 Authentication authentication = request.getAuthentication ( );
161
162 User user = userStore.getUser ( authentication );
163
164 if ( user == null )
165 {
166 if ( request instanceof PullRequest )
167 {
168 return createUserServer.serve (
169 new CreateUserRequest ( authentication ) );
170 }
171
172 return new UnknownUserResponse ( request );
173 }
174
175 user.updateLastRequestTime ( );
176
177 if ( request instanceof PullRequest )
178 {
179 return pullServer.serve ( user, request );
180 }
181
182 user.getRequestQueue ( ).replace ( request );
183
184 return null;
185 }
186
187 //////////////////////////////////////////////////////////////////////
188 // private methods
189 //////////////////////////////////////////////////////////////////////
190
191 private boolean loop ( )
192 //////////////////////////////////////////////////////////////////////
193 {
194 chatGame.update ( );
195
196 long currentTime = System.currentTimeMillis ( );
197
198 synchronized ( this )
199 {
200 if ( DEBUG )
201 {
202 if ( currentTime >= startTime + SAMPLE_PERIOD )
203 {
204 System.out.println ( "requests per second: "
205 + ( MathConstants.MILLISECONDS_PER_SECOND * count )
206 / ( double ) ( currentTime - startTime ) );
207
208 startTime = currentTime;
209
210 count = 0;
211 }
212 }
213
214 if ( currentTime
215 >= lastRequestTime + ChatConstants.REQUEST_TIMEOUT )
216 {
217 if ( DEBUG )
218 {
219 System.out.println ( "ChatServer game loop pausing..." );
220 }
221
222 return false;
223 }
224 }
225
226 return true;
227 }
228
229 //////////////////////////////////////////////////////////////////////
230 //////////////////////////////////////////////////////////////////////
231 }