/*
* Copyright (C) 2009 Muthu Ramadoss. All rights reserved.
*
* Modified from Romain Guy Shelves project to suit Books-Exchange requirements.
* Original source from Shelves - http://code.google.com/p/shelves/
*/
/*
* Copyright (C) 2008 Romain Guy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.androidrocks.bex.provider;
import android.net.Uri;
import android.util.Xml;
import android.view.InflateException;
import android.text.TextUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import com.androidrocks.bex.util.CookieStore;
import com.androidrocks.bex.util.ImageUtilities;
import java.io.InputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.text.ParseException;
class GoogleBooksStore extends BooksStore {
private static final String API_REST_HOST = "books.google.com";
private static final String API_REST_URL = "/books/feeds/volumes";
private static final String API_ITEM_LOOKUP = "q";
private static final String PARAM_MAX_RESULTS = "max-results";
private static final String PARAM_START_INDEX = "start-index";
private static final String VALUE_MAX_RESULTS = "10";
private static final String VALUE_START_INDEX = "1";
private static final String RESPONSE_TAG_FEED = "feed";
private static final String RESPONSE_TAG_ENTRY = "entry";
private static final String RESPONSE_TAG_TOTAL_RESULTS = "totalResults";
private static final String RESPONSE_TAG_IDENTIFIER = "identifier";
private static final String RESPONSE_TAG_TITLE = "title";
private static final String RESPONSE_TAG_PUBLISHER = "publisher";
private static final String RESPONSE_TAG_CREATOR = "creator";
private static final String RESPONSE_TAG_DESCRIPTION = "description";
private static final String RESPONSE_TAG_LINK = "link";
private static final String RESPONSE_TAG_FORMAT = "format";
private static final String RESPONSE_TAG_DATE = "date";
private static final String RESPONSE_ATTR_REL = "rel";
private static final String RESPONSE_ATTR_HREF = "href";
private static final String RESPONSE_VALUE_THUMBNAIL =
"http://schemas.google.com/books/2008/thumbnail";
private static final String RESPONSE_VALUE_INFO = "http://schemas.google.com/books/2008/info";
private static final String RESPONSE_VALUE_PAGES_SUFFIX = "pages";
private final ImageLoader mLoader;
GoogleBooksStore(String name, String label) {
super(name, label, API_REST_HOST);
mLoader = new GoogleImageLoader();
}
@Override
Book createBook() {
return new Book(getName(), mLoader);
}
@Override
Uri.Builder buildSearchBooksQuery(String query) {
final Uri.Builder uri = buildGetMethod();
uri.appendQueryParameter(API_ITEM_LOOKUP, query);
uri.appendQueryParameter(PARAM_START_INDEX, VALUE_START_INDEX);
uri.appendQueryParameter(PARAM_MAX_RESULTS, VALUE_MAX_RESULTS);
return uri;
}
@Override
Uri.Builder buildFindBookQuery(String id) {
final Uri.Builder uri = buildGetMethod();
uri.appendQueryParameter(API_ITEM_LOOKUP, id);
return uri;
}
@Override
void parseResponse(InputStream in, ResponseParser responseParser) throws IOException {
final XmlPullParser parser = Xml.newPullParser();
try {
parser.setInput(new InputStreamReader(in));
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
+ ": No start tag found!");
}
String name = parser.getName();
if (RESPONSE_TAG_FEED.equals(name)) {
responseParser.parseResponse(parser);
}
} catch (XmlPullParserException e) {
final IOException ioe = new IOException("Could not parse the response");
ioe.initCause(e);
throw ioe;
}
}
@Override
boolean parseBook(XmlPullParser parser, Book book) throws XmlPullParserException, IOException {
int type;
String name;
boolean inEntry = false;
boolean isValid = false;
final int depth = parser.getDepth();
if (RESPONSE_TAG_ENTRY.equals(parser.getName())) isValid = inEntry = true;
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
name = parser.getName();
if (RESPONSE_TAG_TOTAL_RESULTS.equals(name)) {
if (parser.next() != XmlPullParser.TEXT || !"1".equals(parser.getText())) {
throw new IOException("Invalid request, 1 result is required");
} else {
isValid = true;
}
} else if (RESPONSE_TAG_IDENTIFIER.equals(name)) {
if (parser.next() == XmlPullParser.TEXT) {
String value = parser.getText();
if (value.startsWith("ISBN:")) {
value = value.substring(5);
switch (value.length()) {
case 10:
book.mIsbn = value;
break;
case 13:
book.mEan = value;
break;
}
} else {
if (book.mInternalId == null) book.mInternalId = value.replace(':', '_');
}
}
} else if (RESPONSE_TAG_ENTRY.equals(name)) {
inEntry = true;
} else if (RESPONSE_TAG_TITLE.equals(name) && inEntry &&
TextUtils.isEmpty(book.mTitle)) {
if (parser.next() == XmlPullParser.TEXT) {
book.mTitle = parser.getText();
}
} else if (RESPONSE_TAG_PUBLISHER.equals(name)) {
if (parser.next() == XmlPullParser.TEXT) {
book.mPublisher = parser.getText();
}
} else if (RESPONSE_TAG_CREATOR.equals(name)) {
if (parser.next() == XmlPullParser.TEXT) {
book.mAuthors.add(parser.getText());
}
} else if (RESPONSE_TAG_DESCRIPTION.equals(name)) {
if (parser.next() == XmlPullParser.TEXT) {
book.mDescriptions.add(new Description("", parser.getText()));
}
} else if (RESPONSE_TAG_LINK.equals(name)) {
final String rel = parser.getAttributeValue(null, RESPONSE_ATTR_REL);
if (RESPONSE_VALUE_THUMBNAIL.equals(rel)) {
final String url = parser.getAttributeValue(null, RESPONSE_ATTR_HREF);
book.mImages.put(ImageSize.THUMBNAIL, url);
book.mImages.put(ImageSize.TINY, url.replace("zoom=5", "zoom=1"));
} else if (RESPONSE_VALUE_INFO.equals(rel)) {
book.mDetailsUrl = parser.getAttributeValue(null, RESPONSE_ATTR_HREF);
}
} else if (RESPONSE_TAG_FORMAT.equals(name)) {
if (parser.next() == XmlPullParser.TEXT) {
String format = parser.getText();
if (format.endsWith(RESPONSE_VALUE_PAGES_SUFFIX)) {
book.mPages = Integer.parseInt(format.substring(0,
format.length() - RESPONSE_VALUE_PAGES_SUFFIX.length()).trim());
}
}
} else if (RESPONSE_TAG_DATE.equals(name)) {
if (parser.next() == XmlPullParser.TEXT) {
final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
book.mPublicationDate = format.parse(parser.getText());
} catch (ParseException e) {
// Ignore
}
}
}
}
isValid = isValid && (book.mIsbn != null || book.mEan != null);
return isValid;
}
@Override
boolean findNextBook(XmlPullParser parser) throws XmlPullParserException, IOException {
if (RESPONSE_TAG_ENTRY.equals(parser.getName())) {
return true;
}
int type;
final int depth = parser.getDepth();
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
if (RESPONSE_TAG_ENTRY.equals(parser.getName())) {
return true;
}
}
return false;
}
/**
* Builds an HTTP GET request for the specified API method. The returned request
* contains the web service path, and the query parameter for the specified method.
*
* @return A Uri.Builder containing the GET path.
*/
private static Uri.Builder buildGetMethod() {
final Uri.Builder builder = new Uri.Builder();
builder.path(API_REST_URL);
return builder;
}
private static class GoogleImageLoader implements ImageLoader {
public ImageUtilities.ExpiringBitmap load(String url) {
final String cookie = CookieStore.get().getCookie(url);
return ImageUtilities.load(url, cookie);
}
}
}