-
Notifications
You must be signed in to change notification settings - Fork 0
/
My_Server.java
347 lines (308 loc) · 11.6 KB
/
My_Server.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class My_Server
*/
@WebServlet("/My_Server")
public class My_Server extends HttpServlet {
private static final long serialVersionUID = 1L;
private static ConcurrentHashMap<String,session> table = new ConcurrentHashMap<String, session>();
private static final String cookie_name = "CS5300PROJ1SESSION";
private static final String DEFAULT_MESSAGE = "Hello World";
private static int environment = 0; //0 for local, 1 for EC2
private final String localSvrID;
// we set k equals to 3 in this case
public static final int data_copies_num = 4;
public static RPC rpc;
public static View view;
private static final int GOSSIP_SECS = 10000;
public static String dataSourceIP;
public My_Server() throws InterruptedException {
super();
//start a new thread that runs hashtable garbage collection
garbage_collection GC= new garbage_collection(table);
GC.start();
//new instance of RPC
rpc = new RPC();
rpc.start();
//get IP
localSvrID = get_IP();
//create view table
view = new View();
view.viewtable.put(localSvrID, new ViewItem(System.currentTimeMillis(), "up"));
view.gossipDB();
//create gossip thread
Gossip gossip = new Gossip();
gossip.start();
}
// Gossip thread
// keep gossiping with other servers or simpleDB
private static class Gossip extends Thread{
public void run() {
try {
while(true){
System.out.println("gossip thread");
view.viewtable.put(get_IP(), new ViewItem(System.currentTimeMillis(), "up"));
Random r = new Random();
Thread.sleep( GOSSIP_SECS/2 + r.nextInt( GOSSIP_SECS+1));
//garbage collect on view table
view.garbageCollect();
System.out.println("after collection:"+view.viewtable);
//random choose one view item or simpleDB to gossip
ArrayList<String> keysAsArray = new ArrayList<String>(view.viewtable.keySet());
int index = r.nextInt(keysAsArray.size()+1);
if(index == keysAsArray.size()){
System.out.println("before gossip with DB");
view.gossipDB();
System.out.println("done gossip with DB");
}else{
System.out.println("before gossip with server");
String serverID = keysAsArray.get(index);
System.out.println("Gossip target IP:"+serverID);
view.gossipServer(serverID);
System.out.println("done gossip with server");
}
}
} catch (InterruptedException e) {
// Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// get_IP using different function by the arg of environment.
public static String get_IP(){
if(environment==0){
return get_localIP();
}else{
return get_AWSIP();
}
}
// get local_ip
public static String get_localIP(){
String ip = null;
try {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface iface = interfaces.nextElement();
// filters out 127.0.0.1 and inactive interfaces
if (iface.isLoopback() || !iface.isUp())
continue;
Enumeration<InetAddress> addresses = iface.getInetAddresses();
while(addresses.hasMoreElements()) {
InetAddress addr = addresses.nextElement();
ip = addr.getHostAddress();
}
}
} catch (SocketException e) {
throw new RuntimeException(e);
}
return ip;
}
//get aws_ip
public static String get_AWSIP(){
try {
Process p = Runtime.getRuntime().exec("/opt/aws/bin/ec2-metadata --public-ipv4");
BufferedReader in = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println("AWS IP Address: "+line);
}
in.close();
return line;
}catch (IOException e) {
e.printStackTrace();
}
return null;
}
//create updated version of the web page according to the sessionData
protected void printPage(HttpServletResponse response,SessionData sessData,String value,boolean flag) throws Exception{
PrintWriter writer=response.getWriter();
response.setContentType("text/html");
writer.write("<html><head><style> table, th, td { border: 1px solid black;border-collapse: collapse;}th, td {padding: 5px;text-align: left;}</style></head>");
String message = "";
if (sessData!=null) message= sessData.message;
writer.print("<body><h1>Message: " + message + "</h1>"+
"<h1>Processing Server: " + get_IP() + "</h1>"+
"<h1>Data Server: " + dataSourceIP + "</h1>"+
"<FORM ACTION='My_Server' method='get' name='form'>"+
"<input type='text' name='message' value=''>"+
"<input type='submit' name='Replace' value='Replace'>"+
"<input type='submit' name='Refresh' value='Refresh'>"+
"<input type='submit' name='Logout' value='Logout'>"+
"</Form></br>"+
view.toString()
);
String curSessID="";
if(sessData!=null){
curSessID = sessData.sessID;
writer.println("<p>SessionID: "+curSessID+"</p>");
writer.println("<p>Version: "+sessData.versionNum+"</p>");
if(sessData.SvrIDs.size() == 0)
writer.println("<p>Data Server(s): None</p>");
else
writer.println("<p>Data Server(s): "+sessData.SvrIDs+"</p>");
if(flag){
writer.println("Session expiration time(minutes): " + Integer.toString(session.get_expiration_time()/60000) + "\n");
}else{
writer.println("<p>Logout ,Current No Session<p/>");
}
writer.println("<p>Session discard time(milliseconds): "+(System.currentTimeMillis()+session.expirationLong)+"</p></body></html>");
}else{
writer.println("<h1>Message: LOGOUT</h1>");
}
}
// check if cookie is valid
private boolean ValidCookie(Cookie c){
String val = c.getValue();
if (val == null )return false;
String[] val_list=val.split("#");
if(val_list.length<3) return false;
if (Integer.parseInt(val_list[1])<0)return false;
return true;
}
//create or find cookie and update information, handle refresh and replace operation
protected void checkCookie(HttpServletRequest request, HttpServletResponse response) throws Exception{
dataSourceIP = get_IP();
// check of coockies
Cookie curCookie = null;
String curCookieVal;
String curSessionID = null;
int curVersion = 0;
ArrayList<String> svrList = null;
Cookie[] cookie_list=request.getCookies();
if(cookie_list!=null) {
System.out.println("lookup cookie");
for (Cookie c: cookie_list){
if(c.getName().equals(cookie_name) && ValidCookie(c)){
curCookie = c;
break;
}
}
}
if(curCookie!=null){
// get cookie information about servers
svrList = new ArrayList<String>();
curCookieVal = curCookie.getValue();
String[] val_list=curCookieVal.split("#");
curSessionID = val_list[0];
curVersion = Integer.parseInt(val_list[1]);
for(int i=2;i<val_list.length;i++){
svrList.add(val_list[i]);
}
}
if(request.getParameter("Logout")!=null){
//logout
System.out.println("Logout!!!!!!!!!!!");
SessionData curSessData=null;
if(curCookie!=null){
curSessData = new SessionData(curSessionID,-1,"Logout Cookie",svrList);
rpc.SessionWriteClient(curSessData,0);
curCookie.setMaxAge(0);
response.addCookie(curCookie);
}
curSessData = null;
printPage(response,curSessData,"",false);
} else {
//replace & refresh
System.out.println("refresh or replace !!!!!!!!!!!");
SessionData curSessData = null;
if(curCookie!=null){
//valid cookie
if(table.containsKey(curSessionID)){
//check local
session curSession = table.get(curSessionID);
if(!curSession.Expired()&&curSession.version>=curVersion){
System.out.println("Local session");
curSessData = new SessionData(curSession,svrList);
}
}
if(curSessData == null){
//no local session or invalid session local
session tmpSess = rpc.SessionReadClient(new SessionData(curSessionID,curVersion,svrList));
if(tmpSess != null)
curSessData = new SessionData(tmpSess,svrList);
}
}
if(curCookie == null||curSessData == null){
//noSession Exist Create
System.out.println("No session exists");
String newSessionID = UUID.randomUUID()+"_"+localSvrID;
svrList = view.availableNodes(data_copies_num, null);
curSessData= new SessionData(newSessionID,0,DEFAULT_MESSAGE,svrList);
}
if(request.getParameter("Replace")!=null){
curSessData.message = request.getParameter("message");
}
//after all operation create cookie and sessions with the sessionData get from above
ArrayList<String> retSvrList = rpc.SessionWriteClient(curSessData,1);
String value=curSessData.sessID + "#" + curSessData.versionNum;
for(String s:retSvrList)
value=value+"#"+s;
curSessData.SvrIDs = retSvrList;
Cookie new_cookie = new Cookie(cookie_name, value);
new_cookie.setMaxAge(session.get_expiration_time()/1000);
response.addCookie(new_cookie);
printPage(response,curSessData,value,true);
}
}
// retrieve session from Sessiontable
public static session retrieve(SessionData sessData){
session tmpSession = table.get(sessData.sessID);
if (tmpSession!=null && sessData.versionNum<=tmpSession.version)
return tmpSession;
else return null;
}
//write session to sessiontable
public static boolean write(SessionData sessData){
if(sessData!=null){
System.out.println("write succ");
session instance=new session(sessData.message,sessData.sessID,sessData.versionNum+1);
System.out.println(table.put(sessData.sessID, instance)!=null);
return table.put(sessData.sessID, instance)!=null;
}else{
System.out.println("write fail");
return false;
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
try {
checkCookie(request,response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
try {
checkCookie(request,response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}