source: other-projects/FileTransfer-WebSocketPair/GWTTomcatSocketServer/src/MyServerEndpoint.java@ 31449

Last change on this file since 31449 was 31449, checked in by davidb, 7 years ago

Adding three project folders for Nathan Kelly's 2016/2017 summer project, experimenting with Websockets for File Transfer with GWT and Sencha GXT

File size: 8.3 KB
Line 
1
2import java.io.File;
3import java.io.FileInputStream;
4import java.io.FileNotFoundException;
5import java.io.IOException;
6import java.nio.channels.NotYetConnectedException;
7import java.util.ArrayList;
8import java.util.logging.Level;
9import java.util.logging.Logger;
10
11import javax.websocket.OnClose;
12import javax.websocket.OnMessage;
13import javax.websocket.OnOpen;
14import javax.websocket.Session;
15import javax.websocket.server.ServerEndpoint;
16
17import org.nbk4.gwt.action.client.ActionObject;
18import org.nbk4.gwt.action.client.ActionObjectBuilder;
19import org.nbk4.gwt.action.client.ActionProperty;
20import org.nbk4.gwt.action.client.ActionRequest;
21import org.nbk4.gwt.action.client.RequestType;
22
23import com.google.gson.Gson;
24
25@ServerEndpoint("/IOtask")
26public class MyServerEndpoint {
27 private static final Gson gson = new Gson();
28 private static final Logger logger = Logger.getLogger(MyServerEndpoint.class.getName());
29 /**
30 * @OnOpen allows us to intercept the creation of a new session.
31 * The session class allows us to send data to the user.
32 * In the method onOpen, we'll let the user know that the handshake was
33 * successful.
34 */
35 @OnOpen
36 public void onOpen(Session session){
37 logger.log(Level.INFO, session.getId() + " has opened a connection", session);
38 //System.out.println(session.getId() + " has opened a connection");
39 sendAlertMessage("Connection has been established to the websocket server!",
40 "Connected to server",
41 session);
42 }
43
44 /**
45 * Sends an alert to the end client. The client cannot respond to the server.
46 * @param message alert message
47 * @param header alert title
48 * @param current connected session
49 * @return True/False - whether or not we could send a response to the user
50 */
51 private boolean sendAlertMessage(String message, String header, Session session) {
52 ActionObject messageToSend = ActionObjectBuilder.messageBoxSpawnObject(header,
53 message, new String[] {"OK"}, false);
54 try {
55 session.getBasicRemote().sendText(gson.toJson(messageToSend));
56 } catch (Exception thrown) {
57 logger.log(Level.WARNING, "could not send error message to user", thrown);
58 return false;
59 }
60 return true;
61 }
62
63 /**
64 * Sends an alert to the end client that provides a server response on user action
65 * @param message The window text to provide the client
66 * @param header The title/header text of the alert
67 * @param session The current user session
68 * @return True/False - whether or not we could send a response to the user
69 */
70 private boolean sendRespondableAlertMessage(String message, String header, Session session) {
71 ActionObject messageToSend = ActionObjectBuilder.messageBoxSpawnObject(header,
72 message, new String[] {"OK", "Cancel"}, true); //push this to using ACTUAL buttons later
73 try {
74 session.getBasicRemote().sendText(gson.toJson(messageToSend));
75
76 MyActionResponseHandler handler = new MyActionResponseHandler(0L, messageToSend.actionID, session);
77 ActionResponseHandler.addHandler(handler);
78 } catch (Exception thrown) {
79 logger.log(Level.WARNING, "could not send error message to user", thrown);
80 return false;
81 }
82 return true;
83 }
84
85 /**
86 * When a user sends a message to the server, this function will intercept the message
87 * and allow us to react to it. For now the message is read as a String.
88 */
89 @OnMessage
90 public void onMessage(String message, Session session){
91 logger.setLevel(Level.ALL);
92 logger.log(Level.FINE, "Message from " + session.getId() + ": " + message);
93
94 try {
95 ActionRequest AR = null;
96 try {
97 AR = gson.fromJson(message, ActionRequest.class);
98 } catch (Exception e) {
99 //if this hasn't completed, or in the case that it ends up null, then we need to warn user
100 logger.log(Level.SEVERE, "Error decoding JSON: ActionRequest did not match " + message, e);
101 AR = null;
102 } finally {
103 if(AR == null) {
104 //warn end user that something is wrong
105 sendAlertMessage("INVALID JSON",
106 "Error decoding JSON: ActionRequest did not match " + message,
107 session);
108 return;
109 }
110 }
111
112 if(!ActionResponseHandler.handleIfResponse(AR)) {
113 ArrayList<ActionProperty> AP = AR.properties;
114
115 if(AR.requestType == RequestType.PROCESS_FILE) {
116 String file_loc_string = "";
117 int file_chunk_size = 0;
118 long file_copy_limit = 0;
119
120 for(ActionProperty property : AP) {
121 switch (property.property) {
122 case FILE_LOCATION_STRING : file_loc_string = property.label; break;
123 case FILE_CHUNK_SIZE : file_chunk_size = Integer.parseInt(property.label); break;
124 case FILE_COPY_LIMIT : file_copy_limit = Long.parseLong(property.label); break;
125 default:
126 break;
127 }
128 }
129
130 handleLoadingBarResponse(file_loc_string, file_chunk_size, file_copy_limit, session);
131 }
132 }
133 } catch (IOException ex) {
134 logger.log(Level.SEVERE, ex.toString(), ex);
135 sendAlertMessage("ERROR",
136 ex.toString(),
137 session);
138 } catch (Exception ex) {
139 logger.log(Level.SEVERE, ex.toString(), ex);
140 sendAlertMessage("ERROR",
141 ex.toString(),
142 session);
143 }
144 }
145
146 private void handleLoadingBarResponse(String location, int chunkSize, long totalSize, Session session) throws Exception {
147 int completed = 0;
148
149 File file = new File(location);
150
151 if(!file.exists()) {
152 sendRespondableAlertMessage("File '" + location + "' doesn't exist - would you like to check again?", "Error", session);
153 return;
154 }
155
156 if(!(file.isFile() && file.canRead())) {
157 sendAlertMessage("File '" + location + "' is not a file or cannot be read", "Error", session);
158 return;
159 }
160
161 FileInputStream f_in = null;
162 try {
163 f_in = new FileInputStream(file);
164 }
165 catch (FileNotFoundException exception) {
166 // A FileNotFoundException translates into a ReadNotPermittedException in this case
167 sendAlertMessage("File '" + location + "' could not be opened", "Error", session);
168 return;
169 }
170
171 byte data[] = new byte[chunkSize];
172 int data_size = 0;
173 boolean first = true;
174 totalSize = Math.min(totalSize, file.length());
175
176 try {
177 while(completed < totalSize && (data_size = f_in.read(data, 0, chunkSize)) != -1) {
178 completed += data_size;
179
180 double progress = totalSize == 0 ? 1.0 : Math.min(1.0, (completed) / (double)(totalSize));
181
182 String message = first ? "Processing "/* + location */+ ": {0}% completed" : null;
183
184 first = false;
185
186 ActionObject loadBarAction = ActionObjectBuilder.loadBarUpdateActionObject(progress, message);
187 String loadBarActionJSON = gson.toJson(loadBarAction);
188
189 session.getBasicRemote().sendText(loadBarActionJSON);
190 }
191 } catch (NotYetConnectedException | IOException e1) {
192 // TODO Auto-generated catch block
193 e1.printStackTrace();
194 }
195
196 try {
197 f_in.close();
198 } catch (IOException e) {
199 // TODO Auto-generated catch block
200 e.printStackTrace();
201 }
202
203 String[] buttons = new String[] {"OK", "Close Window", "Stop!"};
204 ActionObject completedTransferDialog = ActionObjectBuilder.messageBoxSpawnObject("Transfer Successful",
205 "Successfully processed " + location, buttons, false);
206 String messageBoxJSON = gson.toJson(completedTransferDialog);
207
208 session.getBasicRemote().sendText(messageBoxJSON);
209 }
210
211 //TODO: separate file
212 private class MyActionResponseHandler extends ActionResponseHandler {
213 private long myListenerID;
214 private Session session;
215
216 public MyActionResponseHandler(long timeOutMillis, long listenID, Session session) {
217 super(timeOutMillis);
218 myListenerID = listenID;
219 this.session = session;
220 }
221
222 @Override
223 public boolean tryToHandle(ActionRequest request) {
224 logger.log(Level.INFO, "Request ID: " + request.requestID);
225 logger.log(Level.INFO, "My ID: " + myListenerID);
226
227 if(request.requestType == RequestType.RESPONSE_ALERT_WINDOW) {
228 if(myListenerID == request.requestID) {
229 logger.log(Level.INFO, "The user responded to the alert");
230
231 int buttonPress = request.properties.get(0).ID;
232 String button = buttonPress == 0 ? "OK" : "Cancel";
233 sendAlertMessage("You clicked on button " + buttonPress + "/" + button, "Server Response", session);
234 return true;
235 }
236 }
237 return false;
238 }
239 }
240
241 /**
242 * The user closes the connection.
243 * Note: you can't send messages to the client from this method
244 */
245 @OnClose
246 public void onClose(Session session){
247 logger.log(Level.INFO, "Session " +session.getId()+" has ended");
248 }
249}
Note: See TracBrowser for help on using the repository browser.