2

Клиент для Blogger – своими руками-2

Недавно я писал о том, как я начал эксперимент по созданию моего blogger-клиента. На сегодняшний день имеются некоторые крошечные результаты, о которых я собираюсь рассказать.
Не ставя себе сразу умопомрачительную цель, я решил для начала написать маленькую программку, реализующую простую задачу - вывести список постов (заголовки, время публикации и контент) данного пользователя.

После прочтения доки на GData API выяснилось, что список постов будет иметь тип List<Entry>, где Entry - специальный класс, описывающий 1 элемент фида.
Сказано-сделано, скоро был готов примерно такой код:

package blogeditutil;

import com.google.gdata.client.*;
import com.google.gdata.data.*;
import com.google.gdata.util.*;

import java.io.*;
import java.net.*;
import javax.swing.*;
import java.util.*;

public class BlogEditor
{
public static void main(String args[]) throws IOException, ServiceException
{
BlogEditor bedit = new BlogEditor();
String blogname = JOptionPane.showInputDialog(null,
"For example, if blog addresss is lotrex.blogspot.com, input \"lotrex\"",
"Input name of blog");
System.out.print("Blog posts of " + blogname + ":\n");
List<Entry> postlist = bedit.getPostEntryList(blogname);
for(Entry p: postlist)
{
System.out.println("Post caption: " + p.getTitle().getPlainText());
System.out.println("Date and time: " + p.getPublished());
}
}
}

Однако, он (конечно) не компилируется, поскольку метод getPostEntryList(String) в классе BlogEditor не реализован. Я написал код, использующий метод getPostEntryList раньше, чем этот метод был реализован. Немного странно, что я использую интерфейс класса (т.е. его методы) раньше, чем я их реализовал или даже объявил. Но как иначе я могу определить, какой интерфейс будет наиболее удобным? Имхо, самый простой способ придумать интерфейс для класса - написать программку, в которой вы заставляете класс делать то, чего хотите от него добиться, с помощью интерфейса, который (пока) не реализован. При этом я придумываю методы, думаю о том, какие параметры эти методы должны принимать и какие действия они должны выполнять. Так, постепенно у меня формируется представление о том, каким должен быть интерфейс класса (конец лирического отступления, прочитанного менторским тоном:)))

Изучая доку на GData API, я пришел к выводу, что реализовать метод getPostEntryList(String blogname), где параметр blogname - имя блога (в моем блоге это будет строка "lotrex"), используя только интерфейс GData API, и без авторизации, невозможно. Не знаю, в чем тут причина - то ли я чего недосмотрел, то ли разработчики GData API, то ли это политика у Google такая... Но хочется все же иметь возможность читать посты блогов, которые вам интересны.

Для того, чтобы получить фид постов, необходимо знать blogID - строку из нескольких десятичных цифр (чем моложе блог, тем она длинее). Ну что ж, предположим что у нас есть метод getBloggerID(String blogaddr), возвращающий blogID, и попробуем этот blogID распечатать, а использование getPostEntryList() пока уберем:

public static void main(String args[]) throws IOException, ServiceException
{
BlogEditor bedit = new BlogEditor();
String blogname = JOptionPane.showInputDialog(null,
"For example, if blog addresss is lotrex.blogspot.com, input \"lotrex\"",
"Input name of blog");
System.out.println("Blog ID of " + blogname + ":");
System.out.println(bedit.getBloggerID("http://" + blogname +
".blogspot.com"));
}

Пока это все не компилируется - нужно реализовать метод getBloggerID(). В GData API получение blogID без авторизации не предусмотрено, увы :( Строка blogID имеется в коде главной странице блога (пока что), ее легко обнаружить, поискав выражение вида "blogID=XXXXXXXXX". На мой взгляд, этот способ получения blogID вряд ли можно назвать хорошим из-за того, что он в любой момент может перестать работать. Но иного пути, похоже, нет :(((
Поэтому я с (тяжелым сердцем :))) написал довольно простой метод(а точнее - 2 метода), в котором применил именно этот способ:

private String getBloggerID(String blogaddr) throws IOException,
SocketTimeoutException
{
URL blogurl = new URL(blogaddr);
URLConnection connection = blogurl.openConnection();
boolean isconnect = false;
for(int i=0; i < 10; i++)//10 попыток соединения
{
try{
connection.connect();
}catch(SocketTimeoutException ex){
continue;
}
break;
}
connection.connect();
//Создаем класс BufferedReader для чтения по строкам:
BufferedReader bread = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
String str="";
//Читаем ответ сервера по строкам и производим разбор:
//Искать строку, содержащую blogID=xxxxxxx, где xxx - любая цифра
Pattern pat = Pattern.compile("blogID=([\\d]+)");
while( (str = bread.readLine()) != null)
if( (str = getMatch(pat, str)) != null)
break;
bread.close();
//Искать строку, содержащую только цифры:
pat = Pattern.compile("[\\d]+");
return getMatch(pat, str);
}
private String getMatch(Pattern pat, String str)
{
Matcher match = pat.matcher(str);
if(match.find())
return match.group();
return null;
}

Метод длинноват, требует укорачивания, но пока оставим его таким. Чтобы он работал, нужно подключить пакет поддержки регулярных выражений:
import java.util.regex.*;

Компилируем (файл gdata-core-1.0.jar должен находится в текущей директории):
javac -cp .;.\gdata-core-1.0.jar -encoding Cp1251 .\blogeditutil\BlogEditor.java

Если все ОК, то можно запускать:
java -cp .;.\gdata-core-1.0.jarblogeditutil.BlogEditor

Ура, первый шаг сделан - что-то работает, и даже выдает какие-то цифирки, возможно даже, что эти цифирки - тот самый blogID, ради получения которого было написано так много букфф :))) Что ж, теперь у меня получится написать метод, выдающий список блогов:

private final String BLOGGER_FEED = "http://www.blogger.com/feeds/",
POST_LOCATION = "/posts/default",
BLOGGER_SERVER = ".blogspot.com";
private GoogleService bservice;
public BlogEditor()
{
bservice = new GoogleService("blogger", "lotrex-BlogEditor-0.0");
}
public List<Entry> getPostEntryList(String blogname)
throws IOException, ServiceException
{
String blog_id = getBloggerID("http://"+blogname+BLOGGER_SERVER);
if(blog_id == null)
throw new IOException("Can't get blogID for " + blogname+BLOGGER_SERVER);
//Запрос на получение постов:
Query query = new Query(new URL (BLOGGER_FEED + blog_id + POST_LOCATION));
return bservice.getFeed(query, Feed.class).getEntries();
}

Теперь можно заставить работать мой первый вариант метода main(), распечатывающий этот список (тот main(), что в начале статьи). Вставляю его целиком, а предыдущий метод main() закрываю комментами. Компиляция проходит нормально. Запускаю (вывод программки перенаправляю в файл, поскольку на консоль выводятся нечитабельные краказяблы):
java -cp .;.\gdata-core-1.0.jarblogeditutil.BlogEditor >res.txt

Ура, список постов получили!!! Поэкспериментировав с этой программкой, можно заметить, что список выводится не полностью. Когда я опробовал эту прогу впервые, для всех блогов выводилась информация о 15 последних постах (или меньше), счас - о 25(или меньше). Интересно, что теперь, когда я запускаю прогу с моего компа, это число совпадает с числом постов в моем блоге, а раньше это было не так. Возможно, тут дело в настройках блога, а может, и нет :) Думаю, выяснить причину будет несложно - исходные коды GData API открыты. Имхо, это не столь уж важно. Важнее то, что в документации не сказано, как узнать общее количество постов в блоге. Но об этом напишу в следующий раз - эта статья и так получилась слишком длинной.

2 коммент.:

Aleksey комментирует...

Интересно читать описание процесса кодирования. Каждый программист делает это по-своему, и когда знакомишься с ходом чужих рассуждений, учишься чему-то новому.

А если по-простому, то спасибо за пост! =)

Lotrex комментирует...

Спасибо за хороший отзыв! :)

Отправить комментарий