Leveraging Google Data APIs Java client library with GWT
Par Florent le lundi 9 février 2009, 11:48 - GWT - Lien permanent
While the Java client library for Google DATA API can’t be compiled by the GWT compiler, you can still use it in RPC Servlets with the advantage of hiding the protocol or substituting the default authentication backend with yours.
The screenshot below shows an example of a simple GWT application made up of a tree widget displaying my spreadsheets and their worksheets, and a grid widget on which appears the selected worksheet.
The source code of this demo is at the bottom.
Google Data APIs are based on Atom and RSS formats and the Atom Publishing Protocol. Since they are REST-styled, you may use them with any browser:
First we need to authenticate to the service we want to use (Google Spreadsheets in our case) with our Google account. The easiest way is to use the ClientLogin interface:
$ export TOKEN=`curl https://www.google.com/accounts/ClientLogin \ -d Email=cappelle.florent@gmail.com -d Passwd=$GDATA_PASSWORD \ -d accountType=HOSTED_OR_GOOGLE \ -d source=SFEIR-GWTSheets-1 \ -d service=wise | grep 'Auth=' | cut -d'=' -f2`
The service parameter is the Google service we want to use; in this case the «wise» value stands for the spreadsheets service. If the login is successful, the response will include a token which we will use in the next requests. Note that in some cases the service may require a CAPTCHA challenge to be done.
Then we request the list of the spreadsheets we include our token in the Authorization header:
$ curl -H "Authorization: GoogleLogin auth=$TOKEN" \ "http://spreadsheets.google.com/feeds/spreadsheets/private/full" > SpreadsheetList.xml
Querying and editing our spreadsheets this way (you would have to build PUT requests with XML) would be quite inefficient. Instead of parsing XML and building HTTP requests, you may use the Java client library which already does this for you with the SpreadsheetService class:
1 SpreadsheetService sService; 2 sService = new SpreadsheetService("SFEIR-GWTSheets-1"); 3 try 4 { 5 sService.setUserCredentials(email, password); 6 logger.info(email + " authentication successful"); 7 getSession().setAttribute("sService", sService); 8 } catch (AuthenticationException e) 9 { 10 logger.log(Level.WARNING, e.getMessage()); 11 thrownew AuthException(e.getMessage()); 12 }
The preceding piece of code is extracted from a GWT-RPC Service method:
- The «setUserCredentials» method requests a token and stores it in the sService object, which we store in the session for the next requests.
- If the login fails or a CAPTCHA challenge is needed, an AuthException is thrown back to the client.
Once the user is logged in, we build a feed URL with the FeedURLFactory class (see the following piece of code). Its «getSpreadsheetsFeedUrl» returns the URL for the spreadsheet list feed, which then is fetched by the SpreadsheetService object (sService).
1 List<SpreadsheetEntry> spreadsheetEntries = null; 2 FeedURLFactory factory = FeedURLFactory.getDefault(); 3 SpreadsheetFeed feed; 4 5 try 6 { 7 feed = service.getFeed(factory.getSpreadsheetsFeedUrl(), 8 SpreadsheetFeed.class); 9 spreadsheetEntries = feed.getEntries(); 10 getSession().setAttribute("spreadsheetEntries", 11 spreadsheetEntries); 12 } catch (IOException e) ...
The «getEntries» method returns a list of SpreadsheetEntry: Each of these entries contains standard Atom information (author, title, etc) and a worksheet list feed URL. However we don’t even need to build a feed URL since the «getWorksheets» method directly returns a list of WorksheetEntry.
The SpreadSheetModel is a list of Worksheet which is returned to the GWT client: the title and the dimensions of each worksheet are used by the tree and the grid widgets. The cell feed URL is also needed to fetch the content of each cell.
1 SpreadSheetModel model = new SpreadSheetModel(); 2 try 3 { 4 List<WorksheetEntry> worksheetEntries = 5 entry.getWorksheets(); 6 for (WorksheetEntry sheet : worksheetEntries) 7 { 8 model.add(new SpreadSheetModel.WorkSheet( 9 sheet.getTitle().getPlainText(), 10 sheet.getCellFeedUrl().toExternalForm(), 11 sheet.getRowCount(), sheet.getColCount())); 12 } 13 } catch (IOException e) ...
At the client side, the code that fills the tree widget is pretty simple:
1 public void onSuccess(SpreadSheetModel model) 2 { 3 TreeItem item = getItem(position); 4 for (SpreadSheetModel.WorkSheet sheet : model) 5 { 6 TreeItem newItem = item.addItem(sheet.getTitle()); 7 newItem.setUserObject(sheet); 8 } 9 // remove the empty child (see populate method) 10 item.getChild(0).remove(); 11 item.setState(true, false); 12 }
Once the user clicks on a worksheet title in the tree, the worksheet feed URL is given to a RPC method «fetchworksheetcells», which returns a list of cells: the Cell class of the Google API can’t be used as it is in the client side, so we have to copy its properties to a DTO class (WorksheetCell). «copyProperties» of the Apache Commons Beanutils library does this in a single line.
1 List<WorksheetCell> cells = new ArrayList<WorksheetCell>(); 2 try 3 { 4 CellFeed feed = sService.getFeed(new URL(sheetFeedURL), 5 CellFeed.class); 6 List<CellEntry> cellEntries = feed.getEntries(); 7 for (CellEntry entry : cellEntries) 8 { 9 Cell cell = entry.getCell(); 10 WorksheetCell clonedCell = new WorksheetCell(); 11 BeanUtils.copyProperties(clonedCell, cell); 12 cells.add(clonedCell); 13 } 14 } catch (MalformedURLException e) ...
Note that worksheet feeds also have a list feed, which enables relational alike manipulation of worksheet data. Insertion, modification and deletion are very easy with the Java client, for example the modification of a cell entry needs two lines of code:
1 cellEntry.changeInputValueLocal(newValue); 2 cellEntry.update();
Useful Links:
- Spreadsheets service protocol reference: http://code.google.com/intl/fr-FR/apis/spreadsheets/docs/2.0/developers_guide_protocol.html
- Java client library for spreadsheets reference: http://code.google.com/intl/fr-FR/apis/spreadsheets/docs/2.0/developers_guide_java.html
- ClientLogin authentication reference: http://code.google.com/intl/fr-FR/apis/gdata/auth.html#ClientLogin
Article related downloads:
- Demo : Proto GWTSheets
- Java client library source and (very useful) samples: http://code.google.com/p/gdata-java-client/downloads/list
