Back-End

14 nov, 2012

Primeiros passos com Spring Social

Publicidade

Assim como eu, você não vai conseguir deixar de notar a corrida atual para “socializar” aplicativos, seja adicionando um simples botão de “Curtir” do Facebook, um monte de botões de “compartilhar” ou exibir informações na timeline. Todo mundo está fazendo isso, incluindo os caras do Spring, que, como esperado, criaram uma API chamada Spring Social, que permite integrar o seu aplicativo com vários feeds de Software como Serviço (SaaS), como Twitter, Facebook, LinkedIn etc.

Isso, e alguns blogs mostrados a seguir, dá uma olhada em todo o cenário social, demonstrando o uso do Spring Social. Vou começar pelo bem básico.

Se você já viu os Spring Sociais Samples, você vai saber que eles contêm alguns apps “quickstart” muito bons e completos; um para a versão Spring 3.0.x e a 3.1.x. Ao olhar para esses aplicativos, a única coisa que me surpreendeu foi o número de conceitos que você tem que aprender para apreciar o que está acontecendo. Isso inclui configuração, autorização externa, feed de integração, persistência credenciais etc. A maior parte dessa complexidade vem do fato de que o usuário precisa fazer login em sua conta de Software como Serviço (SaaS), como o Twitter, Facebook ou Qzone, de modo que seu aplicativo possa acessar seus dados1. Isso é ainda mais complicado pelo elevado número de fornecedores de SaaS juntamente com o número de diferentes protocolos de autorização que eles utilizam.

Então, eu achei que ia tentar desmembrar isso tudo em vários componentes individuais que explicam como construir um aplicativo útil, no entanto, vou começar com um pequeno background.

A galera do Spring tem percebido que existem tantos provedores de SaaS na Internet que eles nunca serão capazes de codar módulos para todos eles, então eles dividiram a funcionalidade em duas partes, com a primeira compreendendo os módulos spring-social-core e spring-social-web, que fornecem a conectividade básica e o código de autorização para cada provedor de SaaS. Proporcionar tudo isso soa como uma tarefa gigantesca, mas é simplificada, já que não existem muitos protocolos de segurança publicados e, em qualquer caso, a maioria dos provedores SaaS implementa o que é conhecido como protocolo OAuth, que parece ser o padrão de-facto. Ainda não vou entrar em detalhes do OAuth, mas, em poucas palavras, o protocolo OAuth executa um jig um pouco complicado que permite ao usuário compartilhar seus dados SaaS (ou seja, tem no Facebook etc.) com o seu aplicativo sem que ele entregue suas credenciais para o seu aplicativo. Há pelo menos três versões: 1.0, 2.0 e 1.0a, e fornecedores de SaaS são livres para implementar a versão que queiram, muitas vezes, acrescentando suas próprias características exclusivas.

A segunda parte dessa divisão é composta por módulos de provedores de SaaS que sabem como se comunicar com os servidores do provedor de serviços individuais nos níveis mais baixos. O pessoal do Spring atualmente fornece os serviços básicos, o que para mundo ocidental são Facebook, LinkedIn e Twitter. A vantagem de fazer a abordagem extensa modular é que há também todo um conjunto de outras comunidades conduzidas por módulos que você pode usar:

Isso, no entanto, é apenas uma fração do número de serviços disponíveis: para ver o quão grande essa lista é, visite o site AddThis e descubra para quais serviços que eles dão suporte.

De volta ao código

Agora, se você é como eu, quando se trata de programação, você vai odiar segurança: a partir de um ponto de vista de desenvolvimento, é um tempo perdido, impede você de escrever o código e torna a sua vida difícil, então pensei em começar jogando tudo isso fora e escrever um pequeno aplicativo que exibe alguns dados básicos de SaaS. Isso, ao que parece, é possível, pois alguns fornecedores de SaaS, como o Twitter, servem tanto dados públicos como privados. Dados privados são o material que você precisa para logar, enquanto dados públicos estão disponíveis para qualquer um.

Atualmente, eu estou escrevendo um app básico que exibe a timeline de um usuário do Twitter em um aplicativo usando o Spring Social Twitter Module, e tudo que você precisa para fazer isso é um nome de usuário do Twitter.

Para criar o aplicativo, o primeiro passo é criar um Spring Project MVC básico, usando a seção de template do SpringSource Toolkit Dashboard. Isso fornece um web app que vai te ajudar a começar.

O segundo passo é adicionar as seguintes dependências ao seu arquivo pom.xml:

<!-- Twitter API -->
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-twitter</artifactId>
<version>${org.springframework.social-twitter-version}</version>
</dependency>

<!-- CGLIB, only required and used for @Configuration usage: could be removed in future release of Spring -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
</dependency>

A primeira dependência acima é para a API do Twitter do Spring Social, enquanto a segunda é necessária para configurar o aplicativo usando a anotação @Configuration do Spring 3. Note que você também precisará especificar o número de versão da API Twitter, acrescentando:

<org.springframework.social-twitter-version>1.0.2.RELEASE</org.springframework.social-twitter-version>

… para a seção <properties> no topo do arquivo.

O passo 3 é onde você precisa configurar o Spring. Se você olhar para o código de exemplo do Spring Social, vai perceber que os caras do Spring configuram seus aplicativos utilizando Java e a anotação @Configuration do Spring 3. Isso porque a configuração baseada em Java permite muito mais flexibilidade do que a configuração original baseada em XML.

@Configuration
public class SimpleTwitterConfig {

private static Twitter twitter;

public SimpleTwitterConfig() {

if (twitter == null) {
twitter = new TwitterTemplate();
}
}

/**
* A proxy to a request-scoped object representing the simplest Twitter API
* - one that doesn't need any authorization
*/
@Bean
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
public Twitter twitter() {
return twitter;
}

}

Tudo o que o código acima faz é fornecer o Spring com um objeto TwitterTemplate simples através de sua interface Twitter. Usar @Configuration é um exagero para esse aplicativo básico, mas vou desenvolver o assunto em artigos futuros.

Para mais informações sobre a anotação @Configuration e configuração baseada em Java dê uma olhada:

  1. Spring’s Java Based Dependency Injection
  2. More Spring Java based DI

Depois de escrever a classe de configuração, a próxima coisa a fazer é resolver o controller. Neste exemplo simples, eu usei um handler @RequestMapping que lida com URLs que são mais ou menos assim:

<a href=timeline?id=roghughe>Grab Twitter User Time Line for @roghughe</a><br />

…e o código se parece mais ou menos com isto:

@Controller
public class TwitterTimeLineController {

private static final Logger logger = LoggerFactory.getLogger(TwitterTimeLineController.class);

private final Twitter twitter;

@Autowired
public TwitterTimeLineController(Twitter twitter) {
this.twitter = twitter;
}

@RequestMapping(value = "timeline", method = RequestMethod.GET)
public String getUserTimeline(@RequestParam("id") String screenName, Model model) {

logger.info("Loading Twitter timeline for :" + screenName);

List<Tweet> results = queryForTweets(screenName);

// Optional Step - format the Tweets into HTML
formatTweets(results);

model.addAttribute("tweets", results);
model.addAttribute("id", screenName);

return "timeline";
}

private List<Tweet> queryForTweets(String screenName) {

TimelineOperations timelineOps = twitter.timelineOperations();
List<Tweet> results = timelineOps.getUserTimeline(screenName);
logger.info("Fond Twitter timeline for :" + screenName + " adding " + results.size() + " tweets to model");
return results;
}

private void formatTweets(List<Tweet> tweets) {

ByteArrayOutputStream bos = new ByteArrayOutputStream();
StateMachine<TweetState> stateMachine = createStateMachine(bos);

for (Tweet tweet : tweets) {

bos.reset();
String text = tweet.getText();
stateMachine.processStream(new ByteArrayInputStream(text.getBytes()));

String out = bos.toString();
tweet.setText(out);
}
}

private StateMachine<TweetState> createStateMachine(ByteArrayOutputStream bos) {

StateMachine<TweetState> machine = new StateMachine<TweetState>(TweetState.OFF);

// Add some actions to the statemachine
machine.addAction(TweetState.OFF, new DefaultAction(bos));
machine.addAction(TweetState.RUNNING, new DefaultAction(bos));
machine.addAction(TweetState.READY, new ReadyAction(bos));
machine.addAction(TweetState.HASHTAG, new CaptureTag(bos, new HashTagStrategy()));
machine.addAction(TweetState.NAMETAG, new CaptureTag(bos, new UserNameStrategy()));
machine.addAction(TweetState.HTTPCHECK, new CheckHttpAction(bos));
machine.addAction(TweetState.URL, new CaptureTag(bos, new UrlStrategy()));

return machine;
}

}

O método getUserTimeline contém três etapas: em primeiro lugar, ele se apodera de alguns tweets, dá uma formatada e depois coloca os resultados no modelo. Em termos deste artigo, se apodere dos tweets no ponto mais importante e você pode ver que isso é feito no método List<tweet> queryForTweets(String screenName). Esses métodos possuem duas etapas: use o objeto Twitter para se apossar de uma instância TimelineOperations e então use esse objeto para consultar uma timeline utilizando nome de tela do argumento.

Se você observar a interface Twitter, ela age como um objeto factory retornando outros objetos que lidam com diferentes características do Twitter: timelines, mensagens diretas, busca etc. Eu acho que isso é porque os desenvolvedores perceberam que o próprio Twitter engloba tantas funcionalidades que se todos os métodos necessários estivessem em uma classe, eles acabariam tendo um God Object em suas mãos.

Também incluí o passo opcional de conversão dos tweets em HTML. Para fazer isso, eu usei o JAR do meu projeto State Machine, e você pode ver como isso é feito no método formatTweets(…).

Após colocar a lista de Tweets para o modelo como um atributo, a última coisa a fazer é escrever um JSP para exibir os dados:

<ul>
<c:forEach items="${tweets}" var="tweet">
<li><img src="${tweet.profileImageUrl}" align="middle"/><c:out value="${tweet.createdAt}"/><br/><c:out value="${tweet.text}" escapeXml="false"/></li>
</c:forEach>
</ul>

Se você implementar a formatação tag de ancoragem opcional, então a coisa principal a lembrar aqui é garantir que o HTML do Tweet formatado seja captado pelo navegador. Isso é obtido ou usando o atributo escapeXML=”false” da tag c:out ou colocar ${tweet.text} diretamente no JSP.

Eu não incluí qualquer estilo ou um front-end sofisticados neste exemplo, por isso, se você executar o código2, você deve obter algo assim:

E isso completa a minha simples introdução para Spring Social, mas ainda há muita coisa para se falar. No meu próximo artigo, vou dar uma olhada no que está acontecendo no background.

1 Eu estou supondo que existe muita privacidade e questões de legalidade de proteção dos dados a serem levadas em conta aqui, especialmente se você usar essa API para armazenar dados de seus usuários.

2 O código está disponível no GitHub em https://github.com/roghughe/captaindebug/tree/ce33615b3581dc0d35693e46235b3cca422b88ec/social no projeto social.

***

Texto original disponível em http://www.captaindebug.com/2012/06/getting-started-with-spring-social.html