Your task is to implement a calculator web application similar to the one you worked on the Lab 5. The main difference is that in this version, computations will be performed on the server using GWT RPC.

Getting started

Start by downloading CS320_Lab09.zip. Import it into Eclipse (File → Import... → General → Existing projects into workspace → Archive file). You will see a project called CS320_Lab09 in the Package Explorer.

Your Task

Your task is to use GWT RPC to carry out the calculator operations.

You will define support for performing operations to the PerformOperationService RPC service interface.

Step 1 - Define method in the RPC service interface

Add the following method to the PerformOperationService interface:

public OperationResult performOperation(Operation operation);

You will see an error: "PerformOperationServiceAsync is missing method performOperation". Click on the error marker and apply the quick fix ("Generate method 'performOperation' in type 'PerformOperationServiceAsync'").

Step 2 - Implement the RPC call on the server side

You will also need to implement the performOperation method in the PerformOperationServiceImpl class, which is the server-side implementation of PerformOperationService.

This method should instantiate a PerformOperation controller object and an empty OperationResult object, use the controller to perform the operation given as the parameter, and return the OperationResult.

Step 3 - Use the RPC service

In OperationAndResultView, make calls to the RPC service in the handleAdd, handleSubtract, handleMultiply, and handleDivide methods.

These methods already contain code to update the model object (an instance of Operation) based on the values entered in the two text fields and the button pressed by the user. You will need to pass this object as the parameter to the performOperation RPC service method.

The interesting aspect of calling RPC methods is that they are asynchronous: the call sends a request to the server, but does not wait for a response. Instead, an instance of AsyncCallback is provided which has onSuccess and onFailure methods, one of which will be called at a later time when a response is received.

To call an RPC method, you need a proxy object, which is generated by a call to GWT.create. The RPC class defines a proxy object for the PerformOperationService: the performOperationService field contains a reference to a proxy object implementing the asynchronous version of the RPC interface.

Your calls will look something like this:

RPC.performOperationService.performOperation(model, new AsyncCallback<OperationResult>() {
    @Override
    public void onSuccess(OperationResult result) {
        // Your code goes here...
    }
    
    @Override
    public void onFailure(Throwable caught) {
        // Your code goes here...
    }
});

The onSuccess method should update the operationResult object with the value in the result parameter, which is the value returned by the RPC implementation method on the server. Because the ResultView subscribes to state changes from the operationResult, this will automatically update the UI to display the result.

The onFailure method should display an error message. You should add an InlineLabel to the UI to provide a place to display the error message.

Things you should be aware of

All objects that are passed as arguments to RPC methods or returned from RPC methods must implement the Serializable interface. They must only have primitive types or other serializable types as fields. Also, field types may not be superclasses to which objects belonging to subclases will be assigned. E.g., if Car is a subclass of Vehicle, you can't declare a Vehicle field and assign a reference to a Car to the field.

RPC service interfaces should have a RemoteServiceRelativePath annotation that specifies the URL path through which the RPC service will be accessed.

The RPC service implementation class should extend RemoteServiceServlet. It should be declared in /war/WEB-INF/web.xml, specifying an appropriate URL pattern (matching the one specified in the RemoteServiceRelativePath annotation.)