domingo, junho 12, 2011

Google Calendar - Proxy Servlet para adição de agendas externas

Conforme já falei no post anterior sobre o assunto, Google Calendar - Adicionando agendas externas, no google calendar para se fazer a adição de uma url de uma agenda externa é necessário que se utilize um proxy. No post anterior passei o código fonte de um programa na linguagem ASP (Active Server Pages).

Mas agora que cancelei o meu provedor de hospedagem anterior, que suportava ASP, tive que arrumar uma nova solução, de preferencia gratuita.

A escolha foi fazer um servlet em Java e colocar para rodar na estrutura do GAE, Google App Engine. Que é o servidor de apps web do Google, que suporta aplicações escritas em Java, Python e Go e para aplicações que não utilizem muitos recursos você pode usar a infraestrutura do Google de graça.

Foi relativamente simples, apesar do código necessário ser muito maior em Java do que o necessário em ASP.  O único problema que não consegui resolver, devido ao pouco tempo disponível, foi uma exceção de time out. Sim, o GAE - Google App Engine, limita a execução do seu código em no máximo 30 segundos por requisição.

Assim, como o servidor de onde baixo os dados é um pouco lento, tive que apagar alguns registros mais antigos do calendário. Com menos de 5000 registros consegui baixar o arquivo em menos de 30 segundos, contornando temporariamente o problema.
 Apos instalar seu app no google app engine, use a seguinte url para utilizar o sistema:

http://[nome app].appspot.com/AgendaProxy?acesso=[codigo app]

Segue o código do servlet.
Version:1.0 StartHTML:0000000167 EndHTML:0000049823 StartFragment:0000000452 EndFragment:0000049807
import java.io.IOException;

import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.BufferedReader;
import java.io.PrintWriter;

import javax.servlet.http.*;
import javax.servlet.ServletException;

import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.repackaged.com.google.common.util.Base64;

import java.util.logging.Logger;




@SuppressWarnings("serial")
public class AgendaProxyServlet extends HttpServlet {
private static final String HOST = "[servidor do calendário]";
private static final Logger log = Logger.getLogger(AgendaProxyServlet.class.getName());
private static final String versao = "Versão: 1.00";


private HttpURLConnection getConnection(String path, String username, String password, String prot) throws Exception {
String porta = ":443";
prot = prot.toLowerCase();

if (prot!="https") {
prot = "http";
porta = "";
}

URI uri = new URI(prot, HOST, path, null);
URL url = uri.toURL();


log.info("abrindo conexão");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();


connection.setRequestProperty("Host", HOST + porta);
connection.setRequestProperty("Accept", "text/html, */*");
connection.setRequestProperty("User-Agent", "Mozilla/3.0 (compatible; Indy Library)");
connection.setDoOutput(true);
connection.setRequestProperty("Authorization", "Basic "
+ Base64.encode((username + ":" + password).getBytes()));
int timeout=connection.getConnectTimeout();
log.info("time Out:" + timeout);

connection.setConnectTimeout(timeout * 100);
timeout=connection.getConnectTimeout();
log.info("NEW time Out:" + timeout);
return connection;
}
public void service (HttpServletRequest httpRequest,
HttpServletResponse httpResponse)
throws ServletException
{

log.severe("===>" + versao);
String acesso="";
try {
acesso = httpRequest.getParameter("acesso");
}
finally {
if (acesso==null) acesso="";
}
log.info(">acesso:" + acesso);
try {
if (acesso.equals("dmsxyz1234")) {

URLConnection urlConn = getConnection("/[caminho para download sem o nome do servidor]/Calendar", "[nome usuário]", "[senha]","http");


log.info("urlConn:" + urlConn.toString());

// show the client the content type:
log.info("geting contentType");
String contentType = urlConn.getContentType();
log.info("contentType:" + contentType);
httpResponse.setContentType(contentType);
// get the input stream
log.info("abrindo imputStream");
InputStream in = urlConn.getInputStream();
log.info("abrindo buffer de leitura");
BufferedReader br = new BufferedReader(new InputStreamReader(in));
//char[] buffer = new char[1024];
String contentString = "";
log.info("vai iniciar a leitura");
String tmp = br.readLine();

int c = 0;
do
{
c++;
if (c % 5000==0) {
log.info("qt:" + c);
}
contentString += tmp + "\n";
tmp = br.readLine();
}
// while (tmp != null && c<50000);
while (tmp != null);
log.info("qnt de linhas lidas:" + c);
//
// Now write the bytes out to the client.
//
byte[] contentBytes = contentString.getBytes();
OutputStream out = httpResponse.getOutputStream();
log.info("carregando variavel out");
out.write(contentBytes, 0, contentBytes.length);
log.info("Escrevendo variavel out");
out.flush();
out.close();
log.info("fechei, tudo ok");
}
else
{
log.severe ("acesso negado:"+acesso);

try {
PrintWriter pw = httpResponse.getWriter();
pw.println("Acesso negado ! Senha invalida !" + acesso);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
log.severe("erro ao ler o input");
throw new ServletException("Erro durante a escrita: " + e.getMessage());
}
}
}
catch (IOException ioe) {
// on open connection:
log.severe("erro ao abrir conexao");
throw new ServletException("Exception while opening '" + "': " + ioe.getMessage());
}
catch (Exception e) {
// on reading input:
log.severe("erro ao ler o input");
throw new ServletException("Exception during request: " + e.getMessage());
}
}
public static String encode (String source) {
StringBuilder buf = new StringBuilder(source);
byte[] bytes = null;
try {
bytes = buf.toString().getBytes("ISO-8859-1");
} catch (java.io.UnsupportedEncodingException uee) {
assert false;
}
String header = Base64.encode(bytes);
return header;
}
}

Nenhum comentário:

Postar um comentário






Busca do Google

Custom Search