wiki:Contribuicoes/pSync/ManualDesenvolvimento

Manual para desenvolvedores do pSync

O pSync foi totalmente baseado no Foundation, um connector de exemplo disponibilizado pelo Funambol.

Estrutura

Para compilação e geração do plugin pelo ant ( http://ant.apache.org):

  • /build: Estão os ant-files responsáveis pela "compilação" do plugin;
  • /lib: Estão as bibliotecas necessárias para a "compilação" do plugin;

Para compilação e geração do plugin pelo maven ( http://maven.apache.org):

  • pom.xml: O arquivo que contém as propriedades do projeto

Obs: No maven é melhor gerenciado as dependências do projeto, pois permite uso de vários repositórios não dependendo da pasta lib, permite controle das versões, assim como muitas outras integrações que o maven permite, como criar um projeto no Eclipse. Gera o plugin, sem precisar de IDE, na pasta target que o maven cria.

O módulo está dividido em vários diretórios:

  • /src: O código fonte do plugin;
  • /src/main/java/br/com/prognus/psync/: Dentro desse diretório devem estar os seguintes pacotes:
    • admin: São os códigos da interface gráfica, utilizadas na ferramenta de administração do Funambol. Por meio destas é possível criar os SyncSources utilizados pelos clientes (dispositivos);
    • engine/source: Estão as classes que serão invocadas pelo servidor e que são responsáveis pelo tratamento dos dados a serem sincronizados. Dentro de engine ficam os demais pacotes e classes utilizados pelas classes que estão dentro de source;
  • /src/main/sql: Estão contidos os scripts de inicialização dos banco de dados, tanto para o Expresso quanto para o Funambol. Os scripts de cada banco devem estar separados em diretórios com o nome do banco usado;
  • /src/main/config: Estão contidos os scripts de configuração utilizados pelo Funambol para injeção de valores nos atributos;

Foi convencionado que os arquivos desses diretórios sejam nomeados da seguinte forma: Para as interfaces gráficas:

  • <nome>SyncSourceConfigPanel.java;

Para os sources:

  • <nome>SyncSource.java;

Para os scripts:

  • create_engine.sql;
  • drop_engine.sql;
  • init_engine.sql;

As classes SyncSourceConfigPanel derivam do pacote funambol-admin, neste pacote encontram-se as classes usadas na criação da interface de configuração do módulo. As classes SyncSource derivam do pacote funambol-framework, neste pacote encontram-se as classes necessárias para manipular os dados durante a sincronia.

funambol.framework

Este pacote contém os serviços e abstrações usadas em diferentes camadas para implementar o componente. Os serviços mais importantes fornecidos pelo framework são:

  • core: Classes usadas para fazer a tradução de XML para uma arvore de objetos e de uma arvore de objetos para XML;
  • protocol: A comunicação SyncML é uma seqüencia de mensagens correlacionadas seguindo regras adicionais especificadas pelo protocolo SyncML. Este pacote processas as mensagens para assegurar a consistência com o protocolo;
  • logging e security: Implementam os serviços de log segurança;
  • engine: Provê a lógica para o servidor de sincronização, incluindo:
    • Identificar a fonte e o destino dos dados a serem sincronizados;
    • Identificar que dados precisam ser atualizados, adicionados ou removidos;
    • Determinar quantas atualizações devem ser feitas;
    • Detectar e resolver conflitos;

SyncSourceConfigPanel.java

Classes responsáveis pela interface para o gerenciamento das configurações dos SyncSources.
Os SyncSources são os arquivos de configuração responsáveis por indicar quais tabelas serão sincronizadas, os tipos de sincronia permitidos e outras informações.

SyncSource.java

Essas classes são responsáveis por manipular os dados a serem sincronizados, são as classes que fazem a interface entre o servidor Funambol e o banco de dados.

Mapeamento das informações no Expresso Livre

Este wiki tem como finalidade fazer um mapeamento mais detalhado das tabelas utilizadas para armazenar contatos e eventos no banco de dados do Expresso Livre.

Contatos

Os dados dos contatos estão dividos em 25 tabelas, mas em 2 tabelas se encontram todos os dados necessários para o contato. Os dados que poderão ser utilizados no padrão  vCard são os seguintes:

Tabela: phpgw_cc_contact

CampoTipoDescrição
id_contactint8(NOT NULL)[pk]Numero de identificação do contato.
id_ownerint8(NOT NULL)Numero de identificação do dono do contato.
id_statusint4Numero de identificação para contato completo ou simples.
photobyteaValor binário da imagem de exibição do contato.
aliasvarchar(30)Guarda o nome de exibição do contato.
id_prefixint4NULL ( Nenhum dos exemplos criados chegaram a ocupar esse espaço)
given_namesvarchar(100)Guarda o primeiro nome do contato.
family_namesvarchar(100)Guarda o sobre-nome do contato.
names_orderedvarchar(100)Guarda o nome completo do contato.
id_suffixint4NULL ( Nenhum dos exemplos criados chegaram a ocupar esse espaço)
birthdatedateGuarda a data de aniversário do contato.
sexchar(1)Caracter que indentifica o sexo do contato.(nenhum dos exemplos ocupou esse campo, nem havia onde registrar-lo)
pgp_keytextChave publica pgp do contato para criptografia das mensagens.
notestextNotas sobre o contato.
is_globalboolFlag que define se o contato é publico ou privado.

Tabela: phpgw_cc_connections

CampoTipoDescrição
id_connectionint8(NOT NULL)[pk]Numero de identificação da ligação com o contato
connection_namevarchar(50)Guarda o nome do endereço de e-mail ou telefone do contato.
Principal : Para o e-mail principal do contato
Alternativo : para o e-mail alternativo do contato
Residencial : Para o telefone Residencial do contato
Celular : Para o telefone Celular do contato
Comercial : Para o telefone Comercial do contato
Fax : Para o telefone Fax do contato
Pager : Para o telefone Pager do contato
connection_valuevarchar(50)Guarda o valor do e-mail ou telefone do contato.
connection_is_defaultboolDefine se o endereço ou e-mail é o padrão do contato.

Tabela: phpgw_cc_addresses

CampoTipoDescrição
id_addressint8(NOT NULL)[pk]Numero de identificação do endereço
id_cityint8Numero de identificação da cidade
id_stateint8Numero de identificação do estado
id_countrybpchar(2)(NOT NULL)Numero de identificação do pais
address1varchar(60)Endereço principal
address2varchar(60)Endereço secundário
complementvarchar(30)Complemento
address_othervarchar(60)Outro endereço
postal_codevarchar(15)CEP
po_boxvarchar(30)Caixa Postal
address_is_defaultbooleanEndereço é padrão?

As tabelas phpgw_cc_contact e phpgw_cc_connections estão ligadas num relacionamento de 1/N através dessa tabela:
Tabela: phpgw_cc_contact_conns

CampoTipoDescrição
id_contactint8[pk]Guarda a identificação do contato
id_connectionint8[pk]Guarda a identificação da conexão do contato
id_typeof_contact_connectionint4Guarda o tipo de conexao com o contato:
1: Para e-mail
2: Para Telefone

As tabelas phpgw_cc_contact e phpgw_cc_addresses estão ligadas num relacionamento de 1/N através dessa tabela:
Tabela: phpgw_cc_contact_addrs

CampoTipoDescrição
id_contactint8[pk]Numero de identificação do contato
id_addressint8[pk]Numero de identificação do endereço
id_typeof_contact_addressint4Numero de identificação do tipo de endereço:
1 : Para endereço comercial
2 : Para endereço residencial

Calendário

Os dados do calendário estão divididos em 5 tabelas, mas em 2 tabelas podem ser encontradas todas as informações relativas aos eventos.

Tabela: phpgw_cal

CampoTipoDescrição
cal_idint4(NOT NULL)[pk]Numero de identificação do evento.
O valor padrão é dado pela seqüencia nextval(('seq_phpgw_cal'::text)::regclass)
uidvarchar(255)(NOT NULL)Guarda o dominio onde o usuario está inserido ( ex. -@… , joao@… )
ownerint8(NOT NULL)Numero de identificação do dono do evento
categoryvarchar(30)Define se o evento está em alguma categoria.
1 : Para evento com categoria
' ': Para evento sem categoria
groupsvarchar(255)NULL (todos os eventos que foram criados ficaram com esse valor)
datetimeint8Guarda, em microtime, a data e hora em que o evento irá acontecer.
mdatetimeint8Guarda, em microtime, a data e hora em que o evento foi criado.
edatetimeint8Guarda, em microtime, a data e hora em que o evento irá terminar.
priorityint8(NOT NULL)Define a prioridade do evento.
0 : Para evento sem prioridade
1 : Para evento com prioridade baixa
2 : Para evento com prioridade média
3 : Para evento com prioridade alta
cal_typevarchar(10)Define se o evento será repetido.
E : Para evento unico
M : Para evento com repetição
is_publicint8(NOT NULL)Define se o evento será publico.
0 : Para evento particular
1 : Para evento público
titlevarchar(80)(NOT NULL)Guarda o titulo do evento.
descriptiontextGuarda a descrição do evento.
locationvarchar(255)Guarda o local onde o evento irá ocorrer.
referenceint8(NOT NULL)Quando um evento de um evento recursivo é editado, esse campo recebe o cal_id referente ao evento que foi editado.
ex_participantstextGuarda os e-mails dos participantes que não estão em nenhum grupo.
Os participantes estão separados por virgulas.

Essas tabelas tem um relacionamento de 1/1, onde o campo cal_type deve estar com o valor m para que haja uma entrada na tabela abaixo.
Tabela: phpgw_cal_repeats

CampoTipoDescrição
cal_idint8(NOT NULL)Numero de identificação do evento.
recur_typevarchar(30)(NOT NULL)Define o tipo de repetição do evento.
1 : Para evento diário
2 : Para evento semanal
4 : Para evento mensal por dia
3 : Para evento mensal por data
5 : Para evento anual
recur_use_endint80 (Todos os eventos ficaram com esse valor)
recur_enddateint8Guarda, em microtime, a data em que a repetição do evento irá terminar.
recur_intervalint8Guarda o intervalo em que o evento ira ocorrer.
0 : Para um evento unico
1 : Para um evento diario ou semanal ou mensal ( passo de 1 )
2 : Para eventos a cada 2 dias, 2 semanas 2 meses
e assim por diante.
recur_dataint8Guarda quais dias da semana o evento irá acontecer, a somatória desses valores indicará os dias que foram marcados
1 : Domingo
2 : Segunda
4 : Terça
8 : Quarta
16 : Quinta
32 : Sexta
64 : Sabado
(Ex.: 42 = Segunda(2), Quarta(8) e Sexta(32))
recur_exceptionvarchar(255)Guarda, em microtime, os dias em que não haverá o evento.
Esses dias são separados por virgula.

O evento somente será exibido se houver uma entrada nesta tabela indicando a ID do evento e a ID do dono. Tabela: phpgw_cal_user

CampoTipoDescrição
cal_idint8(NOT NULL)Numero de identificação do evento.
cal_loginint8(NOT NULL)Numero de identificação do dono do evento.
cal_statuschar(1)Define se o usuário aceitou ou não participar do evento.
A : Se aceitou participar
U : Se não aceitou participar
cal_typevarchar(1)(NOT NULL)Guarda algum tipo de informação que ainda não foi possível descobrir

Alterações no código e banco de dados do Expresso Livre

Como a solução já está em produção há um bom tempo, as alterações já fazem parte do código do Expresso Livre. De qualquer forma, as alterações do contactcenter estão descritas no ticket #150 e revisão [203], juntamente com outras alterações de internacionalização. Já as alterações do calendar não estão registradas no svn, mas como são poucas alterações, vou colocá-las aqui mesmo:

diff -Naur old/calendar/inc/class.socalendar_sql.inc.php new/calendar/inc/class.socalendar_sql.inc.php
--- old/calendar/inc/class.socalendar_sql.inc.php       2007-03-22 16:58:17.000000000 -0300
+++ new/calendar/inc/class.socalendar_sql.inc.php       2007-10-02 17:12:09.000000000 -0300
@@ -606,6 +606,7 @@
                                        . "',".(int)$event['owner'].','.(int)$event['priority'].','.(int)$event['public'].",'"
                                        . $event['category']."')",__LINE__,__FILE__);
                                $event['id'] = $this->stream->get_last_insert_id('phpgw_cal','cal_id');
+                               $last_status = true;
                        }

                        $date = $this->maketime($event['start']) - $GLOBALS['phpgw']->datetime->tz_offset;
@@ -636,6 +637,7 @@
                                        . "location='".$this->stream->db_addslashes($event['location'])."', "
                                        . ($event['groups']?"groups='".(count($event['groups'])>1?implode(',',$event['groups']):','.$event['groups'][0].',')."', ":'')
                                        . 'reference='.(int)$event['reference'].' '
+                                       . ',last_status = '.($last_status ? "'N'" : "'U'").',last_update = '.time()."000". ' '
                                        . 'WHERE cal_id='.(int)$event['id'];

                        $this->stream->query($sql,__LINE__,__FILE__);

Quanto ao banco de dados, foi necessário realizar algumas alterações conforme os comandos:

ALTER TABLE phpgw_cal ADD COLUMN last_status char(1) DEFAULT 'N'::bpchar;
ALTER TABLE phpgw_cal ADD COLUMN last_update int8 DEFAULT (date_part('epoch'::text, ('now'::text)::timestamp(3) with time zone) * (1000)::double precision);

ALTER TABLE phpgw_cc_contact ADD COLUMN last_status char(1) DEFAULT 'N'::bpchar;
ALTER TABLE phpgw_cc_contact ADD COLUMN last_update int8 DEFAULT (date_part('epoch'::text, ('now'::text)::timestamp(3) with time zone) * (1000)::double precision);
ALTER TABLE phpgw_cc_contact ADD COLUMN category character varying(20);

Attachments