/*
* @copyright 2012 Philip Warner
* @license GNU General Public License
*
* This file is part of Book Catalogue.
*
* Book Catalogue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Book Catalogue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Book Catalogue. If not, see <http://www.gnu.org/licenses/>.
*/
package com.eleybourn.bookcatalogue.goodreads.api;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import oauth.signpost.exception.OAuthCommunicationException;
import oauth.signpost.exception.OAuthExpectationFailedException;
import oauth.signpost.exception.OAuthMessageSignerException;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import com.eleybourn.bookcatalogue.goodreads.GoodreadsManager;
import com.eleybourn.bookcatalogue.goodreads.GoodreadsManager.Exceptions.BookNotFoundException;
import com.eleybourn.bookcatalogue.goodreads.GoodreadsManager.Exceptions.NetworkException;
import com.eleybourn.bookcatalogue.goodreads.GoodreadsManager.Exceptions.NotAuthorizedException;
import com.eleybourn.bookcatalogue.goodreads.api.XmlFilter.ElementContext;
import com.eleybourn.bookcatalogue.goodreads.api.XmlFilter.XmlHandler;
/**
* Class to add a book to a shelf. In this case, we do not care about the data returned.
*
* ENHANCE: Parse the result and store it against the bookshelf in the database.
* Currently, this is not a simple thing to do because bookshelf naming rules in
* goodreads are much more restrictive: no spaces, punctuation (at least).
*
* Need to add the following to bookshelf table:
* - gr_bookshelf_id
* - (perhaps) gr_bookshelf_name
*
* @author Philip Warner
*
*/
public class ShelfAddBookHandler extends ApiHandler {
public ShelfAddBookHandler(GoodreadsManager manager) {
super(manager);
buildFilters();
}
private long mReviewId = 0;
/*
* <shelf>
* <created-at type='datetime' nil='true'></created-at>
* <position type='integer' nil='true'></position>
* <review-id type='integer'>254171613</review-id>
* <updated-at type='datetime' nil='true'></updated-at>
* <user-shelf-id type='integer'>16480894</user-shelf-id>
* <name>read</name>
* </shelf>
*/
/**
* Add the passed book to the passed shelf
*/
public long add(String shelfName, long grBookId)
throws ClientProtocolException, OAuthMessageSignerException, OAuthExpectationFailedException, OAuthCommunicationException, IOException,
NotAuthorizedException, BookNotFoundException, NetworkException
{
return doCall(shelfName, grBookId, false);
}
/**
* Remove the passed book from the passed shelf
*/
public long remove(String shelfName, long grBookId)
throws ClientProtocolException, OAuthMessageSignerException, OAuthExpectationFailedException, OAuthCommunicationException, IOException,
NotAuthorizedException, BookNotFoundException, NetworkException
{
return doCall(shelfName, grBookId, true);
}
/**
* Do the main work; same API call for add & remove
*/
private long doCall(String shelfName, long grBookId, boolean isRemove)
throws ClientProtocolException, OAuthMessageSignerException, OAuthExpectationFailedException, OAuthCommunicationException, IOException,
NotAuthorizedException, BookNotFoundException, NetworkException
{
mReviewId = 0;
HttpPost post = new HttpPost("http://www.goodreads.com/shelf/add_to_shelf.xml");
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
if (isRemove)
parameters.add(new BasicNameValuePair("a", "remove"));
parameters.add(new BasicNameValuePair("book_id", Long.toString(grBookId)));
parameters.add(new BasicNameValuePair("name", shelfName));
post.setEntity(new UrlEncodedFormEntity(parameters, "UTF8"));
// Use a parser based on the filters
XmlResponseParser handler = new XmlResponseParser(mRootFilter);
// Send call. Errors will result in an exception.
mManager.execute(post, handler, true);
return mReviewId;
}
private void buildFilters() {
/* Typical output.
<shelf>
<created-at type='datetime'>2012-01-02T19:07:12-08:00</created-at>
<id type='integer'>167676018</id>
<position type='integer'>13</position>
<review-id type='integer'>255221284</review-id>
<updated-at type='datetime'>2012-01-02T19:07:12-08:00</updated-at>
<user-shelf-id type='integer'>16737904</user-shelf-id>
<name>sci-fi-fantasy</name>
</shelf>
*/
// We only care about review-id:
XmlFilter.buildFilter(mRootFilter, "shelf", "review-id").setEndAction(mHandleReviewId);
}
private XmlHandler mHandleReviewId = new XmlHandler() {
@Override
public void process(ElementContext context) {
try {
mReviewId = Long.parseLong(context.body.trim());
} catch (Exception e) {
// Ignore?
}
}
};
}