180 likes | 312 Views
Project Scenario for OpX. High-level Overview. In the Test GUI Controller, opXController , for the opX command there is conceptually a call to an appropriate Class , C , of the form OpXResponseInfo opXResponse = C.opX ( OpXRequest );
E N D
High-level Overview In the Test GUI Controller, opXController, for the opX command there is conceptually a call to an appropriate Class, C, of the form OpXResponseInfoopXResponse = C.opX(OpXRequest); Where OpXRequst is an instance of OpXRequestInfo. Then we show the response in the response window with IView.setResponse(opXResponse.toString());
Things to Understand • First, things to do in the OpXController of the GUI is to get ready to make the call • The class, C, is not on the same machine as the GUI. So, how do we call the operation across the internet? • We use a client and a server • We call the opX command on the client communicator, CC. OpXResponseInfoopXResponse = CC.opX(opXRequest); • The client communicator encodes the operation and its parameters (opXRequest) and sends them to the server. • The server gets the operation and parameters (bundled in the object opXRequest) and decodes them. • The server then calls C.opX(opXRequest) and gets a response, opXResponse, of type OpXResponseInfo
Getting Ready to make the call • Get the parameters from the GUI • Use IView.getParameters() • Use them to create an instance of OpXRequestInfo, opXRequest • I have a constructor whose single parameter is the output of IView.getParameters() • OpXRequestInfoopXRequest = new OpXRequestInfo(Iview.getParameters) • Get a string representation of the opXRequest • String stringRepresentation = opXRequest.toString(); • Use IView.setRequst(stringRepresentation) to display the string in the GUI
Calling the opX operation across the Internet • We use a client and a server • In the opXController we call the opX command in the client communicator, CC. OpXResponseInfoopXResponse = CC.OpX(OpXRequest); • The client communicator encodes the operation and its parameters (opXRequest) and sends them to the server. • The server gets the operation and parameters (bundled in the object opXRequest) and decodes them. • The server then makes the call we wanted to make in the first place OpXResponseInfoopXResponse = C.opX(opXRequest) • The server then encodes the response and sends it back to the client • The client communicator then decodes the response (opXResponse) as the return value for the method call made in the opXController.
The Client Communicator Design • There exists one method for every operation opX. • OpXRequestInfoopX(OpXRequestInfoopXRequest) • Each of the methods for the 7 commands are all most identical. • We will take all of the common code and put it in its own method which we will call “doPost” • If done well, the OpXResponseInfoopX(OpXRequestInfo) method becomes a one liner: return (OpXResponseInfo) doPost(opXName, opXRequest)
The “doPost” method • First, set up the connection • Encode the opXRequest and send it • Handle any problems (the connection failed, the response is not OK, or the response is empty). • Decode the response as an object and send it to the opX method that called “doPost”
Setting up the Connection • Create a string representation of the address of the server • http://localhost:8080/ + opXName • opXName is an input parameter to doPost • Create a URL URL url = new URL(the string you just created) • Create HttpURLConnection HttpURLConnection connection = (HttpURLConnection)url.open(); • The HttpURLConnection class is in the Java library
Setting up the Connection(Continued) • Set the request method type connection.setRequestMethod(“POST”); • Indicate there will be information in the body of the request connection.setDoOutput(true); • Now connect connection.connect();
Encoding and Sending using XStream • Encode and store in the body of the request xStream.toXML(opXRequst, connection.getOutputStream()) • The opXRequest is a parameter to doPost • The xStream is an instance of XStream • Send the request to the server connection.getOutputStream.close();
Handling the Response • Get the response code connection.getResponseCode() • Get the response length connection.getResponseLength() • If everything is correct • Decode the response and store it in an object Object object = xStream.fromXML(connection.getInputStream) • Return the object to the opX method that called doPost (the calling method then casts the object to the appropriate type)
Handling Errors • Use a try/catch block • Throw errors for • Response code not equal to HttpURLConnection.HTTP_OK • contentLength not equal to 0 • IOException • Thrown when trying to connection or communicate
The Server Perspective • Create a Server class containing a HttpServer we will call httpServer. • When you set up the server • Initialize anything that you need • For example, initialize the datebase • You may need to use the DataImporter to fill the Database • Create the HttpServer HttpServerhttpServer= HttpServer.create(new InetSocketAddress(8080), 10) • Set the Executor httpServer.setExecutor(null) • Create the contexts for each command. For the opX command it might be httpServer.createContext(“/opX”, opXHandler); • There are 7 such commands • The name of the operation is the one appended to the end of the url string in the client • There is one context (“/”, fileTransfer) for the 8th command. • The opXHandler is described on the next page • Start the server • server.start()
Server Handlers • Each of the handlers is an instance of a subClass of the library class HttpHandler abstract public HttpHandler { public HttpHandler(){} abstract void handle(HttpExchange exchange); } • Create an HttpHandler for every operation opX. This is done in the Server class • Do this by subclassingHttpHandler, overloading the handle method, and creating an instance. This is best done using an anonymous inner class. • Assign it to a variable name of your choice which is the name used when creating a context (see previous slide) • Example private HttpHandleropXHandler = new HttpHandler() { public void handle(HttpExchange exchange) throws IOException { //see next slide } }
The Body of every Handler • Retrieve and decode the request OpXRequestInfoopXRequestInfo = (OpXRequestInfo)xStream.fromXML(exchange.getRequestBody()) • The xStream is a variable in the Server class • The exchange is the input parameter in the handle method • getRequestBody() actually gets an InputStream • Execute the operation on the appropriate class OpXResponseInfoopXResponse = C.opX(opXRequestInfo) • Encode the response and send it back to the client communicator • First, set the headers Exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, 0); • Endcode and write the response to the response body xStream.toXML(opXResponse, exchange.getResponseBody()) • getResponseBody actually returns an OutputStream • Send the response exchange.getResponseBody.close();
Handling Errors on the Server Side • Wrap everything in try/catch block • Catch IOExceptions when creating the server • Catch any exceptions thrown when the operation in the model class is called • If there is an error send and error response back exchange.sendResponseHeaders( HttpURLConnection.HTTP_INTERNAL_ERROR, -1) • You don’t have to write anything to the response body (using xStream.toXML) nor do you perform exchange.getResponseBody().close()
The opX operations in the Server • This is up to you • I use a single Class called Controller that has a method for each of the 8 commands • Most of the logic should go here • Including error detection and reporting • The database access classes should primarily by “getters” and “setters” • The may be of a higher level and thus not match one for one with sql commands on a table.
The 8th CommandFileDownload Command • Differences • We don’t really use the “/opX” method of identifying the corresponding handler for file downloading • You might consider httpServer.createContext(“/”, fileDownloader); • The fileDownloader doesn’t encode the response. • It opens up the output file (an OutputStream) of the exchange • It also opens the source file as an InputStream. • It then copies the contents of the source file into the output stream of the exchange • When finished, it closes the OutputStream.