: : www.mundoj.com.br : : Geração de compromissos com Java usando o padrão iCalendar Décio Heinzelmann Luckow ([email protected]): é bacharel em Sistemas de Informação pela Univille e pós-graduando em Gestão de Projetos pela Sustentare Escola de Negócios. Já trabalhou com as linguagens ASP, PHP, Python e tem se especializado nas tecnologias Java, atuando no desenvolvimento Web e integração de sistemas. Possui as certificações Java SCJP 1.5 e SCWCD. Atua como analista de sistemas na TOTVS, na área de Inteligência Empresarial. É autor do livro Programação Java para a Web da editora Novatec, além de artigos pela revista MundoJ. Aprenda a gerar compromissos via Java e enviá-los para programas como Google Calendar e Mozilla Sunbird. Este artigo apresentará o padrão iCalendar, que é o formato para envio de agendamentos utilizado em ferramentas de calendário como Google Calendar e Mozilla Sunbird, entre outras. Entenderemos as principais opções do formato iCalendar, como enviar agendamentos via e-mail com Java e como criar calendários disponíveis na internet. geração de agendamentos é algo que pode ser muito bem explorado em diversos tipos de aplicativos. Como, por exemplo, podemos citar: aviso de pagamentos de contas, agendamento de consultas médicas ou aviso de eventos. Utilizando o padrão iCalendar é possível enviar estes agendamentos por e-mail ou criar um serviço de calendário na internet e sempre manter a sua agenda atualizada. Este é o formato adotado por programas como Google Calendar e Mozilla Sunbird, o que garante um grande campo de adoção deste recurso. Neste artigo aprenderemos a enviar e-mails em Java no formato iCalendar e como criar um serviço de calendário na internet. O formato iCalendar O formato iCalendar foi criado pelo Internet Engineering Task Force no Calendaring and Scheduling Working Group em 1998. A última atualização do formato ocorreu em setembro de 2009. Este formato tem como objetivo definir agendamentos que po- 32 dem ser enviados via arquivo, via e-mail ou compartilhados na internet. Um exemplo básico de um agendamento pode ser conferido na Listagem 1. Listagem 1. Exemplo de agendamento simples no formato iCalendar. BEGIN:VCALENDAR VERSION:2.0 METHOD:REQUEST PRODID:-//Revista MundoJ//Teste do artigo //PT BEGIN:VEVENT UID:evento001-javaparaweb.com.br DTSTART:20110415T183000 DTEND:20110415T203000 SUMMARY:Ler a revista MundoJ END:VEVENT END:VCALENDAR Este exemplo cria um agendamento com o assunto “Ler revista MundoJ” que ocorrerá entre as 18h30 e 20h30 do dia 15/04/2011. Um objeto iCalendar sempre irá começar com BEGIN:VCALENDAR e finalizar com END:VCALENDAR. Este mesmo padrão de BEGIN e END também é adotado por outros agrupadores de informações do agendamento, que oficialmente são chamados de componentes de calendário. O exemplo da Listagem 1 possui o VEVENT que descreve o evento em si. Porém, além deste, ainda existem também os componentes VTODO, VJOURNAL, VFREEBUSY, VTIMEZONE e VALARM. De todos estes componentes apenas o VCALENDAR, VEVENT e VALARM são implementados pela maioria dos aplicativos de calendário. O VALARM permite configurar como deverá funcionar o aviso do compromisso, com ele você pode definir que 15 minutos antes do compromisso, deve exibir uma janela de aviso, ou tocar um determinado som. Este trecho de código que define o agendamento pode ser disponibilizado de três formas básicas: por um arquivo com a extensão .ics, via e-mail ou via serviço de calendário. Porém, antes de explorarmos as várias formas existentes para se compartilhar um agendamento, vamos estudar um exemplo mais completo e conhecer a finalidade de cada parâmetro do iCalendar. Opções do VCALENDAR O VCALENDAR é o elemento principal de um iCalendar, suas principais propriedades são: t 7&34*0/o&TQFDJmDBBWFSTÍPEBFTQFDJmDBÎÍPEPJ$BMFOEBS a versão atual é a 2.0. A informação é obrigatória. t .&5)0% o &TQFDJmDB RVF UJQP EF USBOTBÎÍP P BSRVJWP PV e-mail do agendamento irá realizar. Para o envio por e-mail é obrigatório que se tenha um METHOD especificado também no Content-Type da mensagem de e-mail. Estes dois METHOD devem sempre ter o mesmo valor (veremos mais detalhes sobre isso ao fazer o envio do agendamento por e-mail). t 130%*%o²BJEFOUJmDBÎÍPEPQSPEVUPRVFHFSPVPBHFOEBmento. Não existe um formato obrigatório, mas recomenda-se usar o seguinte padrão: PRODID:-//Nome da Empresa//Nome do Aplicativo//Idioma Opções do VEVENT O VEVENT especifica o evento em si, este deverá estar dentro de um VCALENDAR e só poderá ter um VALARM dentro dele. Suas principais propriedades são: t $"5&(03*&4 o &TQFDJmDB VNB DBUFHPSJB QBSB P BHFOEBmento. Alguns dos valores padrões são: ANNIVERSARY, APPOINTMENT, BUSINESS, EDUCATION, HOLIDAY, MEETING, NON-WORKING HOURS, NOT IN OFFICE, PERSONAL, PHONE CALL, TRAVEL, VACATION. t $-"44 o &TQFDJmDB VNB DMBTTJmDBÎÍP EF BDFTTP BP BHFOEBmento, por parte de outros usuários. Os valores possíveis são: PUBLIC, PRIVATE e CONFIDENTIAL. t $0..&/5 o 6N UFYUP MJWSF DPN VN DPNFOUÈSJP TPCSF P agendamento. t 46.."3:o0BTTVOUPEPBHFOEBNFOUP t %&4$3*15*0/ o 6NB EFTDSJÎÍP QBSB P BHFOEBNFOUP NBJT completa que o SUMMARY. t (&0o*OGPSNBVNBQPTJÎÍPHMPCBMQBSBBBUJWJEBEFBHFOEBEB é composta pela latitude e longitude, respectivamente. ExemQMP (&0 .VTFV EF "SUF EF 4ÍP Paulo). t -0$"5*0/o6NUFYUPMJWSFTPCSFPMPDBMEPFWFOUP&YFNplo: LOCATION: Sala de reunião 12, terceiro andar. t 13*03*5:o&TQFDJmDBBQSJPSJEBEFEPBHFOEBNFOUPFNRVF 0 é o mais prioritário e 9 é o menos prioritário. t 3&4063$&4 o 6NB MJTUB TFQBSBEB QPS WÓSHVMB EPT FRVJQBmentos necessários para o evento. Exemplo: PROJETOR, AUDIO, TELEFONE. t 45"564o&TQFDJmDBPTUBUVTEPFWFOUPQPEFOEPTFSVNEPT valores: TENTATIVE, CONFIRMED e CANCELLED. t %545"35 o &TQFDJmDB B EBUBIPSB EF JOÓDJP EP FWFOUP "Tsim como todas as propriedades de data, deve ser descrito no formato: AAAAMMDD’T’HHMMSS ou algumas variações para data e hora absoluta e com fuso horário, conforme os exemplos: DTSTART:20110415T133000 (hora local) DTSTART: 20110415T173000Z (hora absoluta, ou a hora no Meridiano de Greenwich) %545"355;*%"NFSJDB/FX@:PSL 5 (com especificação de fuso horário) Se for um evento de um dia, mas sem hora definida (exemplo: data de aniversário), deve ser especificado o DTSTART no padrão AAAAMMDD e sem DTEND. t %5&/%o&TQFDJmDBBEBUBIPSBEFmNEPFWFOUP t %63"5*0/ o &TQFDJmDB B EVSBÎÍP EP FWFOUP DPOGPSNF B ISO8601, exemplo: P15DT5H0M20S – 15 dias, 5 horas e 20 segundos P1DT12H45M – 1 dia, 12 horas e 45 minutos P2W – 2 semanas t 53"/41 o *OEJDB TF P FWFOUP JSÈ PDVQBS FTQBÎP OB BHFOEB ou apenas ficará registrado, deixando o seu período livre para mais compromissos. Usará o valor OPAQUE para ocupar a agenda, senão deve ser TRANSPARENT para ficar registrado, mas deixando o horário livre para novos agendamentos. O padrão é OPAQUE. t 03("/*;&3o*OEJDBPPSHBOJ[BEPSEPFWFOUP4FDPMPDBSPT seus dados como ORGANIZER e enviar o e-mail do agendamento para si mesmo, este não será absorvido pelo aplicativo de calendário, pois parte-se do princípio que como você é o organizador o agendamento partiu daquele aplicativo. ExemQMP 03("/*;&3$/%ÏDJP -VDLPXNBJMUPEFDJPMVDLPX! gmail.com. t 6*%o²PJEFOUJmDBEPSÞOJDPEPBHFOEBNFOUPÏBUSBWÏTEFMF que o aplicativo de calendário irá saber quando recebeu uma atualização para um mesmo UID. Deve-se pensar um valor para este campo que não se repita no mundo. O aconselhável é que seja alguma composição com domínio, por exemplo: agenda003_javaparaweb.com.br. Utilizando um domínio próprio é mais difícil dele se repetir no destino. t $3&"5&% o &TQFDJmDB RVBOEP P BHFOEBNFOUP GPJ DSJBEP Não tem relação com a data de início ou de fim. t -"45.0%*'*&%o&TQFDJmDBRVBOEPPBHFOEBNFOUPGPJNPdificado pela última vez, usa o mesmo formato de data do DTSTART. 33 : : www.mundoj.com.br : : t 4&26&/$& o &TQFDJmDB B TFRVÐODJB EF BMUFSBÎÍP EP BHFOdamento. No momento da criação – se for informado – deve ser 0. Se for enviada (por e-mail) alguma atualização deste agendamento deverá ser incrementado, para cada alteração enviada. Listagem 2. Exemplo de agendamento completo. BEGIN:VCALENDAR PRODID:-//Software SA//Agenda Corporativa//PT VERSION:2.0 Opções do VALARM METHOD:REQUEST BEGIN:VEVENT O VALARM especifica como você será avisado do seu compromisso. Ele deve obrigatoriamente conter as propriedades ACTION e TRIGGER, além de outras opcionais. t "$5*0/o$POmHVSBRVBMBÎÍPEFWFTFSUPNBEBQBSBBWJTBS do compromisso. Pode ter os valores AUDIO, DISPLAY ou EMAIL. o AUDIO – Quando utilizado pode incluir uma propriedade ATTACH que deve apontar para um arquivo de áudio que será reproduzido quando o alarme for disparado. o DISPLAY – Quando utilizado pode incluir a propriedade DESCRIPTION. Esta propriedade conterá o texto que será exibido quando o alarme for disparado. o E-MAIL – Quando utilizado deve obrigatoriamente incluir as propriedades DESCRIPTION como o corpo do e-mail e SUMMARY como o assunto do e-mail, dentro do VALARM. Um ou mais ATTENDEE como destinatários e opcionalmente um ATTACH para o e-mail que será enviado. t 3&1&"5 o $POmHVSB RVBOUBT WF[FT P BMBSNF EFWF TFS SFQFtido, depois do primeiro disparo. Se o valor for maior que um deve configurar também a propriedade DURATION, no mesmo padrão da DURATION do VEVENT. t 53*((&3o$POmHVSBRVBOEPPBMBSNFTFSÈEJTQBSBEP4FSÈ um valor negativo para disparar antes e positivo para depois da DTSTART. Tem o mesmo formato da propriedade DURATION. Exemplos: TRIGGER:-PT15M – Quinze minutos antes. 53*((&33&-"5&%&/%15.o$JODPNJOVUPTEFQPJTEP final do evento. t "55&/%&& o %FmOF PT EFTUJOBUÈSJPT DBTP P BMBSNF TFKB P envio de e-mail. Exemplo: ATTENDEE:mailto:[email protected]. Para colocar mais destinatários deve-se repetir a propriedade em mais linhas. t "55"$)o%FmOFVNBSRVJWPBOFYPBPBHFOEBNFOUP/FTUF caso será o arquivo de áudio associado ao alarme. Exemplo: FMTTYPE=audio/basic:ftp://servidor.com.br/pub/sounds/ alarme.aud Explorando um exemplo completo A Listagem 2 apresenta um exemplo mais completo de agendamento, que contempla também um VALARM. Por mais que todo desenvolvedor tenha vontade de endentar o código-fonte deste VCALENDAR isto tornará o arquivo inválido. Além disso, principalmente se tratando de uma geração a partir de sistema, é necessário que cada propriedade tenha uma quebra de linha no final. Devemos dar atenção especial à propriedade DESCRIPTION. Para incluir quebra de linha deve ser adicionado o caractere \n. Para que esta propriedade ocupe mais linhas dentro do objeto iCalendar é necessário deixar dois espaços em branco na frente das linhas posteriores. 34 UID:reuniao023-minhaempresa.com.br ORGANIZER;CN="Administrador":mailto:[email protected] DTSTART:20110414T140000 DTEND: 20110414T160000 LOCATION:Sala de Reunião 3 SEQUENCE:0 STATUS:CONFIRMED CATEGORIES:APPOINTMENT SUMMARY:Reunião de resultados do trimestre DESCRIPTION:Avaliação dos indicadores \ne tomada de ação para o próximo trimestre PRIORITY:5 CLASS:PUBLIC BEGIN:VALARM TRIGGER:-PT15M ACTION:DISPLAY END:VALARM END:VEVENT END:VCALENDAR Enviando por e-mail O envio por e-mail é com certeza a aplicação mais interessante para a geração de agendamentos. Porém este recurso tem algumas particularidades que garantirão que o aplicativo que receberá o e-mail reconheça esta mensagem como um agendamento. O e-mail enviado terá um conteúdo do tipo text/calendar e no formato UTF-8, que é o padrão para o formato iCalendar. Além disso, o e-mail enviado não precisa ter assunto e corpo, o aplicativo de calendário irá considerar o SUMMARY e DESCRIPTION do agendamento recebido. Para o funcionamento do envio de e-mail, o projeto Java na sua IDE preferida precisa ter os jars do Java Mail API e Java Activation Framework, que podem ser obtidos nos endereços http://www. oracle.com/technetwork/java/index-138643.html e http://www. oracle.com/technetwork/java/javase/jaf-136260.html. Estas duas bibliotecas necessárias têm como objetivo atender exclusivamente ao envio de e-mail no Java, não existe qualquer requisito específico para a geração do agendamento. Veja na Listagem 3 como implementar o envio de e-mail de agendamento no Java. Listagem 3. Exemplo de envio de agendamento por e-mail. package br.com.mundoj.calendar; import java.util.Properties; import javax.activation.*; import javax.mail.*; import javax.mail.internet.*; import javax.mail.util.*; public class CalendarMail { public static void main(String[] args) throws Exception { Properties config = new Properties(); config.put(“mail.smtp.host”, “smtp.servidor.com.br”); config.put(“mail.smtp.port”, “25”); Neste exemplo, a montagem do arquivo do iCalendar é feita dentro de um StringBuffer, perceba que sempre ao final de cada linha adicionamos um \n, para incluir a quebra de linha obrigatória. Ao criar o ByteArrayDataSource, obtemos o conteúdo do StringBuffer usando o método getBytes(“UTF-8”) o que garante que não ocorram problemas de acentuação no agendamento. Além EJTTPPTFHVOEPQBSÉNFUSPDPOUÏNPUFYUPUFYUDBMFOEBSNFUIPE 3&26&45DIBSTFU65'&TUFUFYUPJOEJDBPNJNFUZQFUFYU calendar, o method que deve ser sempre igual ao METHOD do agendamento e o charset. O código restante adiciona o conteúdo como agendamento como um conteúdo do e-mail. Para enviar este e-mail usando um servidor de e-mail autenticado, consulte o quadro “Enviando e-mail com autenticação”. Na figura 1 pode ser visto como este agendamento foi recebido no Gmail, que se integra automaticamente ao Google Calendar. Session session = Session.getDefaultInstance(config); MimeMessage mimeMessage = new MimeMessage(session); mimeMessage.setFrom(new InternetAddress( “[email protected]”)); mimeMessage.addRecipients(Message.RecipientType.TO, “[email protected]”); mimeMessage.addRecipients(Message.RecipientType.TO, “[email protected]”); StringBuffer sb = new StringBuffer(); sb.append(“BEGIN:VCALENDAR\n”); sb.append(“PRODID:-//Revista MundoJ//Teste do artigo//PT\n”); sb.append(“VERSION:2.0\n”); sb.append(“METHOD:REQUEST\n”); sb.append(“BEGIN:VEVENT\n”); sb.append(“UID:reuniao023-minhaempresa.com.br\n”); sb.append(“ORGANIZER;CN=\”Diretor Comercial\”:mailto: [email protected]\n”); sb.append(“DTSTART:20110415T203000\n”); sb.append(“DTEND:20110415T210000\n”); sb.append(“LOCATION:Sala de reunião 3 - Térreo\n”); sb.append(“STATUS:CONFIRMED\n”); sb.append(“CATEGORIES:APPOINTMENT\n”); sb.append(“SUMMARY:Reunião gerencial\n”); sb.append(“DESCRIPTION:Elaboração de nova \\nestratégia comercial\n”); sb.append(“ para o próximo trimestre\n”); sb.append(“END:VEVENT\n”); sb.append(“END:VCALENDAR”); ByteArrayDataSource ds = new ByteArrayDataSource(sb.toString(). getBytes(“UTF-8”), “text/calendar;method=REQUEST;charset=\”UTF-8\””); DataHandler dh = new DataHandler(ds); Multipart multipart = new MimeMultipart(); MimeBodyPart mimepart = new MimeBodyPart(); mimepart.setDataHandler(dh); multipart.addBodyPart(mimepart); mimeMessage.setContent(multipart); Transport.send(mimeMessage); } } Figura 1. Agendamento recebido no GMail e Google Calendar. Criando um arquivo Um agendamento também poderia ser transportado por meio de um arquivo simples. Para isso, bastaria gerar um arquivo com um conteúdo no mesmo padrão da Listagem 2 e nomeá-lo como .ics (Internet Calendar Service). Ao acionar este arquivo em um computador com algum aplicativo de calendário, este será aberto, bastando aceitar o agendamento para que ele entre na sua agenda. Criando um serviço de calendário Um serviço de calendário é um recurso existente em aplicativos como o Google Calendar ou o Mozila Sunbird que permite manter a agenda sempre sincronizada com informações de calendário disponíveis na internet. Estas informações de calendário devem ser disponibilizadas por meio de uma URL que aponte para um arquivo no formato iCalendar. Este não precisa ser necessariamente um arquivo físico, as informações podem também ser geradas sob demanda, o importante é que sejam no formato iCalendar. Um exemplo de URL poderia ser http://www.seudominio.com.br/eventosjava_ical.jsp, ao chamar este endereço, um conteúdo no formato iCalendar seria devolvido. Para que um arquivo possa conter informações de mais de um agendamento ao mesmo tempo deve seguir o padrão conforme a Listagem 4. 35 : : www.mundoj.com.br : : Listagem 4. Formato para serviço de calendário BEGIN:VCALENDAR PRODID:-//Software SA//Agenda Corporativa//PT VERSION:2.0 METHOD:REQUEST Enviando e-mail com autenticação Caso o seu servidor de e-mail utilize autenticação, serão necessárias algumas linhas de código a mais. Estas linhas adicionam a propriedade mail.smtp.auth como true e inclui as informações de autenticação, conforme a Listagem 5. BEGIN:VEVENT [...] END:VEVENT BEGIN:VEVENT [...] END:VEVENT BEGIN:VEVENT Listagem 5. Autenticação para envio de e-mail. Properties config = new Properties(); config.put(“mail.smtp.host”, “smtp.servidor.com.br”); config.put(“mail.smtp.port”, “25”); config.put(“mail.smtp.auth”, “true”); [...] END:VEVENT END:VCALENDAR Perceba que este arquivo contém somente um elemento VCALENDAR e dentro dele vários VEVENT que deverão conter as informações dos agendamentos em si. Para adicionar um calendário da internet no Google Calendar vá em Outras Agendas > Adicionar > Adicionar por URL e informe a URL do calendário. No Mozilla Sunbird vá em Arquivo > Inscrever em calendário remoto. Selecione a opção “Na Rede” quanto a localização do calendário e depois a opção “iCalendar (ICS)” para o formato, e informe a URL. Atualizando um agendamento Para o envio de agendamento por e-mail, caso este tenha que ser atualizado é necessário seguir algumas regras. Para o serviço de calendário na internet isto não é necessário, pois a sincronização é constante. Sempre que for necessário enviar uma nova versão de um agendamento por e-mail, deve ser dada especial atenção ao UID. Esta propriedade identificará unicamente o agendamento, permitindo atualizar um agendamento já existe e não criar um novo. Além disso, a propriedade SEQUENCE deve ser incrementada conforme as atualizações forem enviadas. Por padrão, esta propriedade tem o valor 0, se for enviada uma atualização o seu valor tem que ser 1, depois 2 conforme forem enviadas mais atualizações. Todas as propriedades do agendamento devem ser enviadas e não somente aquelas que sofreram alteração. Cancelando um agendamento No "cancelando", a propriedade UID tem a mesma função da atualização de agendamento. Porém no caso de um cancelamento a propriedade METHOD deve ser enviada como CANCEL tanto no corpo do VCALENDAR quanto na linha de envio de e-mail, FYFNQMPUFYUDBMFOEBSNFUIPE$"/$&-DIBSTFU65' Além disso, a propriedade STATUS no corpo do VEVENT deve ter o valor CANCELLED. Todas as propriedades do agendamento devem ser enviadas, mesmo que seja apenas um cancelamento. 36 javax.mail.Authenticator autenticacao = new javax.mail.Authenticator() { @Override protected javax.mail.PasswordAuthentication getPasswordAuthentication() { return new javax.mail.PasswordAuthentication(“usuario”, “senha”); } }; Session session = Session.getDefaultInstance(config, autenticacao); Livro Programação Java para a Web Este artigo apresentou o padrão iCalendar, que é um recurso muito interessante para agregar funcionalidade ao seu aplicativo. Com ele, é possível integrar o seu produto aos aplicativos de calendário já utilizados por seus usuários, como o Google Calendar, Mozilla Sunbird, Microsoft Outlook, Lotus Notes, entre outros. Como exemplo de uso pode-se citar: avisos de pagamento, agendamento de consultas médicas e qualquer outro tipo de compromisso. Esta abordagem de utilizar exemplos interessantes para ensinar Java também é adotada pelo livro Programação Java para a Web da editora Novatec (www.javaparaweb.com. br). Este livro possui uma temática inovadora, com enfoque extremamente prático, que mostra passo a passo como desenvolver uma aplicação web utilizando a linguagem Java e as tecnologias mais poderosas e populares no arsenal dos desenvolvedores, como JavaServer Faces e Hibernate. O método utilizado no livro se baseia no projeto de uma aplicação financeira pessoal, em que são abordadas várias técnicas de desenvolvimento em cada etapa do projeto, desde as mais tradicionais e conhecidas até as mais modernas e avançadas. O artigo apresenta recursos que podem complementar seus próprios projetos e o projeto abordado no livro, tornando-os ainda mais interessantes. Além disso, o livro também aborda os requisitos básicos de um sistema construído de forma profissional em Java, como: JavaServer Faces, Hibernate, Facelets, CSS, Spring Security, Ajax, PrimeFaces, internacionalização, iReport e Jasper Reports, JfreeChart, WebServices e busca de informações em meios externos. Considerações finais Este artigo mostrou um recurso muito interessante tanto para aplicativos web quanto desktop. Seu objetivo não foi esgotar este assunto, mas mostrar as configurações mais comuns para seu uso. Além disso, mostrou algumas opções de disponibilização dos caMFOEÈSJPTFOWJBOEPQPSFNBJMQPSBSRVJWPFWJBJOUFSOFUt Referências -JWSP1SPHSBNBÎÍP+BWBQBSBB8FC-VDLPX%ÏDJP)FJO[FMNBOO.FMP"MFYBOESF"MUBJSEF&EJUPSB/PWBUFD -JTUBEFBQMJDBUJWPTRVFBDFJUBNJ$BMFOEBSIUUQFOXJLJQFEJBPSHXJLJ-JTU@PG@ BQQMJDBUJPOT@XJUI@J$BMFOEBS@TVQQPSU J$BMFOEBSOB8JLJQÏEJBIUUQFOXJLJQFEJBPSHXJLJ*$BMFOEBS &TQFDJmDBÎÍPPmDJBMEPJ$BMFOEBSIUUQUPPMTJFUGPSHIUNMSGD GUJ – Discussões sobre o tema do artigo e assuntos relacionados Discuta este artigo com 100 mil outros desenvolvedores em www.guj.com.br/MundoJ 37