Google

quinta-feira, janeiro 05, 2012

De volta?

E assim, 4 anos depois do último post, estou de volta. Mas vale a pena? Twitter e Facebook é tão mais fácil. Se bem que aqui é mais direcionado, né? Vejamos o que vai acontecer...

quarta-feira, outubro 01, 2008

O melhor é OpenSolaris e o Virtual Box




De volta da evangelização promovida pela Sun, desinstale seu Windows, pq o melhor é o OpenSolaris e o Virtual Box. Ah, claro que não se deve usar Eclipse e sim NetBeans 6.1. hehehehehe

Brincadeira (e das grandes)! Delpheiros devem amar a Sun! Diferente de programadores de verdade! hehehehe

Dá uma olhada nisso (muito comentado no evento):

  • EJB 3.0 e as mágicas do EJB 3.1,
  • jMaki (Framework Ajax),
  • Diamond-powder (Framework para JME),
  • SuperCRUD (compatilhamento de arquiteturas JEE open source), e
  • JavaFX (para UI, mas só pra conhecer mesmo, pq é um rascunho do protótipo de uma versão beta)

segunda-feira, setembro 15, 2008

Sun Tech Days 2008

Próxima parada: São Paulo. Sun Tech Days 2008!


Exibir mapa ampliado

quinta-feira, julho 17, 2008

Como construir um socket em linguagem C e Java

Resumo
Este projeto, o servidor de correio eletrônico, tem como objetivo trabalhar a programação de serviços orientados a conexão, mostrando a criação do circuito virtual e a transferência de dados entre processos servidores e clientes por meio de um protocolo conhecido. A aplicação será chamada de Send E-Mail.

Tecnicamente, o servidor de correio funciona como um serviço por trás de uma porta. Nas outras sessões deste documento, serão apresentados trechos de código que detalham cada processo da criação desse circuito lógico.

Introdução
A comunicação entre processos em máquinas diferentes, muita das vezes em locais diferentes, separadas por centenas de kilômetros de distância, requer a identificação dessas máquinas e a definição de protocolos de comunicação.

A arquitetura TCP/IP provê a estrutura necessária para essa comunicação, através dos sockets. Neste projeto, seguimos alguns passos e conjuntos de propriedades para dar suporte aos serviços orientados a conexão pelos sockets.

Sintaticamente, devemos seguir o seguinte processo:


  1. Criação de um objeto socket, a partir do qual serão criadas as conexões;

  2. Atribuição de um endereço lógico ao socket do processo host. Basicamente é necessário um IP ou um nome de servidor e uma porta;

  3. Preparação do socket para aceitar novas conexões no endereço previamente atribuído;

  4. E por fim, o socket é colocado para aguardar novas conexões.



Veja o diagrama abaixo, que ilustra os processos descritos acima, aplicados aos requisitos do servidor de correio (definidos a diante):



Requisitos do servidor de correios
Primando por facilidade de implementação e definição de protocolo de comunicação, o Send E-Mail trabalha com a mensagem inteira, ou seja, após efetuar a conexão com o servidor, o programa cliente envia toda a mensagem, encapsulada em um XML.

Assim, ao receber os bytes enviados pelo cliente, o servidor cria um processo filho que manipula este XML, armazenando a mensagem em uma estrutura de diretórios, conforme mostrado anteriormente no diagrama.

O servidor de correios Send E-Mail deve:

  1. Receber conexões de programas clientes na porta 1000, intencionalmente em localhost;

  2. Ler mensagem recebida do cliente no seguinte formato:
    <email to=”emailto@domain.com” from=”emailfrom@domain.com”>
    <content subject=”subject of message”>body of message</content>
    </email>

  3. Instanciar processo que recebe mensagem XML e armazena no sistema de arquivos.



Nota: A escolha do endereço localhost é didática. Como o socket é de domínio Internet e a família de endereços é IP, este nome poderia ser qualquer endereço válido, conforme especificação IP.

Veremos a seguir como foram implementados o servidor e o cliente do Send E-Mail.

Implementação do Send E-Mail
Inicialmente o projeto foi desenvolvido na linguagem Java, tanto a implementação do servidor quanto do cliente (inclusive a interface gráfica com usuário). Posteriormente para aprofundar os conhecimentos das diretivas de baixo nível da comunicação por socket, uma nova implementação foi feita, em linguagem C.

Linguagem C
Em C foram criados três projetos: EMailServer, EMailClient e EMail. O EMailServer é o servidor que aguarda conexões de EMailClient. Ao enviar a mensagem, o EMailServer instancia EMail que manipula a mensagem e a armazena no sistema de arquivos.

Há apenas um programa principal em EMailServer. Neste programa, criamos um socket, uma estrutura de endereço, preparamos o socket para receber as conexões do cliente e manipulamos a mensagem.

Precisamos preencher a estrutura do endereço local, ou seja, do servidor que irá escutar as conexões. Dizemos a família de endereços, que aceitaremos conexões de qualquer endereço na porta 1000 (definido em #define SERVER_PORT):

laddr.sin_family = AF_INET;
laddr.sin_addr.s_addr = htonl(INADDR_ANY);
laddr.sin_port = htons(SERVER_PORT);
memset(&(laddr.sin_zero), '\0', 8);


Logo após criamos o socket. Neste ponto, devemos informar o tipo de endereço aceitável, qual seu domínio e o protocolo a usar:

if((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < saddr_len =" sizeof(struct" ns =" accept(sd," xmlfrombuffer =" (char" bytes_readed =" read(ns,"> 0) {
total_bytes_readed += bytes_readed;
xmlFromBuffer = strcat(xmlFromBuffer, buffer);
xmlFromBuffer = realloc(xmlFromBuffer, strlen(xmlFromBuffer) + MAX_BUFFER);
}
xml = (char *)calloc(total_bytes_readed, sizeof(char));
memcpy(xml, xmlFromBuffer, total_bytes_readed);
free(xmlFromBuffer);

close(ns);

if(execl("/root/Documents/EMail/Debug/EMail", "", xml, NULL) < 0) { perror("Can't execute EMail!"); exit(-1); } exit(0); }


O EMailClient é um módulo que recebe cinco argumentos: from, to, subject e content. Com esses argumentos, o XML do protocolo de comunicação é montado. Logo após, o EMailClient tenta efetuar conexão com o servidor EMailServer. Em sucesso, todo XML é enviado. Veja:

if(argc < 5) { perror("Usage: EMail ");
exit(-1);
}
if((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < sin_family =" AF_INET;" sin_port =" htons(PORT);" sin_addr =" *((struct">h_addr);
bzero(&(saddr.sin_zero),8);

to = argv[1];
from = argv[2];
subject = argv[3];
content = argv[4];

char *CONST_TO = "";
char *CONST_END = "";

xmlToSend = (char *)calloc(strlen(CONST_FROM) + strlen(from) + strlen(CONST_TO) + strlen(to) + strlen(CONST_SUBJECT) + strlen(subject) + strlen(CONST_CONTENT) + strlen(content) + strlen(CONST_END), sizeof(char));

xmlToSend = strcat(xmlToSend, CONST_TO);
xmlToSend = strcat(xmlToSend, to);
...
if(connect(sd, (struct sockaddr *)&saddr, sizeof(struct sockaddr)) < 0) { perror("Client: Connect"); exit(1); } send(sd, xmlToSend, strlen(xmlToSend), 0); close(sd);


O último passo é armazenar a mensagem no sistema de arquivos. Isso é feito pelo módulo EMail. Ele recebe um único argumento, que é a mensagem encapsulada no XML. Ao extrair o atributo to do XML, é criado um diretório dentro de emails (diretório onde todas as mensagens são armazenadas) com o respectivo valor.

Logo após, um arquivo com extensão XML é criado dentro deste novo diretório, cujo nome segue o padrão: .xml. Assim, em tese, é praticamente impossível ter duas mensagens com mesmo nome. E essa tipologia organiza de forma trivial as mensagens por data de recebimento. Veja abaixo o trecho de extração do atributo do XML:


aux_to = strchr(argv[1], quote);
to = (char *)malloc(sizeof(char));
do {
to = realloc(to, (strlen(to) + 1) * sizeof(char));
to[new_source++] = aux_to[source++];
} while(aux_to[source] != '\"');


Linguagem Java
Grande parte do trabalho feito em C é abstraído pela máquina virtual de Java. Sendo assim, algumas características importantes na atribuição do tipo de conexão ou mesmo no estabelecimento do protocolo de comunicação ficam implícitos na implementação de um servidor nesta linguagem.

Devido às facilidades de desenho da interface com o usuário, alguns recursos extras foram adicionados nesta implementação. Por exemplo, é possível definir a porta na qual o servidor será levantando, assim como o diretório padrão onde serão salvas as mensagens.

Adotando o paradigma de programação orientado a objetos, o projeto passa a contar com cinco classes, distribuído em dois pacotes. No pacote br.ufu.facom.mail estão as classes de serviço, responsável por implementar os requisitos funcionais do projeto. Em br.ufu.facom.ui, fica a classe que pinta a interface com o usuário.

A classe EMail.java é um POJO que contém as informações da mensagem. A classe EMailServer.java contém a regra de negócio da conexão: Ao receber uma conexão da classe EMailClient.java essa classe cria uma nova thread para tratar essa conexão e armazenar a mensagem no sistema de arquivos. Esse último serviço é feito pela classe StoreEMail.java.


public class EMail {
private String from;
private String to;
private String subject;
private String content;
private Element message;
...
}


O objeto serverSocket escuta conexões na porta definida pela variável port e cria novas threads para manipular o armazenamento da mensagem no sistema de arquivos. Veja:


public class EMailServer implements Runnable {
...
public void run() {
try {
serverSocket = new ServerSocket(port);
while(!terminate) {
socket = serverSocket.accept();
StoreEMail storeEMail = new StoreEMail(socket, directory);

new Thread(storeEMail).start();
}
} catch (IOException ignored) {
}
}
...
}


O cliente cria um socket no endereço address na porta port, e através de um buffer escreve o XML neste socket e fecha-o. Veja:


public class EMailClient {
...
public void sendEMail() throws Exception {
socket = new Socket(address, port);
out = new DataOutputStream(socket.getOutputStream());
buffer = new StringBuffer();

if(message == null) {
throw new Exception("Não há mensagem a enviar!");
}

prepareMessageInBufferToSend();

out.writeUTF(buffer.toString());

out.flush();
out.close();
socket.close();
}
...
}


Esta classe é invocada pelo servidor na thread que trata as conexões de entrada. Assim como na solução em C, o sistema cria um diretório dentro de emails com o nome do destinatário e armazena a mensagem pela data de recebimento. Veja:


public class StoreEMail implements Runnable {
...
public void run() {
try {
in = new DataInputStream(socket.getInputStream());
buffer.append(in.readUTF());
email = new EMail(buffer);
saveEmail();
in.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
} catch (JDOMException e) {
e.printStackTrace();
}
}

private void saveEmail() throws IOException {
XMLOutputter out = new XMLOutputter();
File userDirectory = new File(directory, email.getTo());
userDirectory.mkdir();
File emailFile = new File(userDirectory, getNameOfFile(email.getSubject()));
FileWriter writer = new FileWriter(emailFile);
out.output(email.getMessage(), writer);
writer.flush();
writer.close();
}

private String getNameOfFile(String subject) {
StringBuffer nameOfFile = new StringBuffer();

DateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
Date date = new Date();

nameOfFile.append(dateFormat.format(date));
nameOfFile.append(".xml");

return nameOfFile.toString();
}
}


Conclusões
Os serviços orientados a conexão são de extrema valia quando é necessário manter um circuito virtual entre duas pontas, ou seja, garantir a troca mensagens de maneira segura e confiável entre um servidor e um cliente.

Conhecer a abstração que o sistema operacional faz no nível da camada de rede pode ser de fundamental importância para garantir o desempenho de sistemas e evitar erros e desperdícios de espaço e tempo (armazenagem e transferência), em se tratando de aplicações cliente/servidor.

O uso de linguagens de programação deve estar diretamente ligado com o propósito da solução, uma vez que abstrações destas linguagens podem levar a resultados errôneos em aplicações de baixo nível, tal qual a construção de serviços atrás de portas.

Por último, a definição de um protocolo de comunicação para gerir serviços baseados na comunicação por rede é de suma importância, pois pode evitar erros, simplificar a programação e até aperfeiçoar os recursos despendidos no processamento da informação nas duas pontas.

Apêndice
Foram enviados por email os arquivos fonte e executáveis das soluções apresentadas. Veja abaixo detalhes para execução de cada solução.

Para rodar a solução em C (projeto_c.zip)
Para testar a solução escrita em C, rode o EMailServer sem argumentos. Para enviar uma mensagem, rode o EMailClient com os seguintes argumentos: EMailClient . O executável EMail deve estar em /tmp.
Para rodar a solução em Java (projeto_java.zip)
Descompacte o conteúdo em um diretório e digite a seguinte linha:


java -cp forms-1.2.0.jar;jdom.jar;send.jar br.ufu.facom.ui.SendEMail


Nota: A solução em Java possui uma interface amigável com o usuário, na qual é possível listar os e-mails que estão no servidor, assim como lê-los e removê-los. Apesar de ter o botão para iniciar o servidor em C, esse recurso não foi implementado. Para fazer qualquer operação pela interface gráfica, é necessário rodar o servidor. Toda a interface está no idioma Inglês.

Nota: Os arquivos forms-1.2.0.jar e jdom.jar são bibliotecas de terceiros que auxiliam no desenvolvimento da interface e na leitura e escrita de arquivos XML, respectivamente. São necessários para executar a solução em Java.

Referências bibliográficas

  1. Stallings, William. Arquitetura e Organização de Computadores. 1ª edição. Editora: Pearson Ed. ISBN: 8587918532

  2. Tanenbaum, Andrew S. Redes de Computadores. 4ª edição. Editora: Campus. ISBN: 8535211853

  3. Deitel, H. M. Como Programar em C. Editora: LTD. ISBN: 8521611919

  4. http://www.cs.cf.ac.uk/Dave/C/

  5. API specification for version 6 of the Java™ Platform, Standard Edition.



Qualquer dúvida é só falar!
Solicite os fontes por e-mail.

Bom final de semana!

segunda-feira, maio 05, 2008

Criando Componentes com Estilos Personalizáveis

No post anterior foi relatado em detalhes a definição, a diferença e como gerar temas e estilos compilados usando o Flex Builder e o prompt de comando pelo compilador. Agora será explicado como adicionar propriedades personalizadas de estilo aos componentes.

Vamos tomar como base, o componente de pesquisa. Ele é composto por um label, um campo de código, uma imagem (que chama a ação de abrir a tela de pesquisa) e mais um campo de texto (com a descrição do código do campo anterior). Veja a imagem abaixo:

Este componente estende um VBox, adicionando um Label, um TextInput, uma Image e mais um TextInput. A imagem acima é a apresentação padrão deste componente. No entanto, poderíamos criar um tema no qual a imagem da ação de abrir a tela de pesquisa fosse outra. Poderíamos também, dar enfoque ao campo de código, ao invés do campo de descrição, deixando-o maior. Essas são algumas propriedades passíveis de estar num seletor CSS. Veja algumas alternativas para este componente:

Ou,
Propriedades como x, y, width e height são propriedades do UIComponent, não estilos. E por esse motivo não podem ser setados através de CSS, em tese. Digo em tese, pois podemos simular, usando algum método de invalidate e seu respectivo tratamento no render posterior.

Há três passos para criar os estilos personalizáveis:

  1. Na classe MXML ou no arquivo .as do componente, colocar a meta informação do estilo;
  2. Definir os valores padrão das propriedades de estilo que estão sendo criadas;
  3. Sobrescrever o médoto styleChanged.

Vejamos a seguir os detalhes de cada passo.

Primeiro Passo: Style metadata tag
Devemos usar a tag [Style] antes da definição de classe, num arquivo .as, ou dentro do bloco <mx:metadata>, de um MXML. A sintaxe dessa tag é a seguinte:

[Style(name="style_name"[,property="value",...])]

Veja abaixo a descrição das propriedades da tag [Style], conforme o guia de desenvolvimento da Adobe:

Seguindo nosso exemplo com o componente de pesquisa, devemos adicionar as seguintes tags:

[Style(name="searchIcon", type="Class", inherit="no")]
[Style(name="disabledSearchIcon", type="Class", inherit="no")]
[Style(name="inputCodeWidth", type="Number", inherit="no")]

Segundo Passo: Valores padrão das propriedades
Vamos definir três propriedades de classe que conterão os valores (inclusive o padrão) dos estilos. Veja:

[Embed(source="assets/img/search.png")] private var _searchImg:Class;
[Embed(source="assets/img/search_dis.png")] private var _searchImgDisabled:Class;
private var _inputCodeWidth:Number = 80;

Como são propriedades privadas, devemos criar os métodos get e set, conforme abaixo:

public function get searchImg():Class { return _searchImg; }
public function get searchImgDisabled():Class { return _searchImgDisabled; }
public function get inputCodeWidth():Number { return _ inputCodeWidth; }

public function set searchImg(searchImg:Class):void {
_searchImg = searchImg;
}
public function set searchImgDisabled(searchImgDisabled:Class):void {
_searchImgDisabled = searchImgDisabled;
}
public function set inputCodeWidth(inputCodeWidth:Number):void {
_inputCodeWidth = inputCodeWidth;
}

Devemos usar essas propriedades na criação dos filhos ou nos métodos correspondentes aos invalidates. Isso servirá para deixar nosso componente com uma aparência agradável mesmo quando não se usar estilos. É como se fosse um Hallo Theme, comparando-se com o que acontece no Flex.

Terceiro Passo: Sobrescrever o método styleChanged
Após definir o padrão, devemos sobrescrever o método styleChanged. Assim, podemos pegar as propriedades setadas na defnição do estilo, esteja ela onde estiver (num arquivo CSS, no corpo do documento ou inline). Veja abaixo:

override public function styleChanged(styleProp:String):void {
super.styleChanged(styleProp);

var searchIconStyle:Class = getStyle("searchIcon");
var disabledSearchIconStyle:Class = getStyle("disabledSearchIcon");
var inputCodeWidthStyle:Number = Number(getStyle("inputCodeWidth"));

if(searchIconStyle != null){
_searchImg = searchIconStyle;
}

if(disabledSearchIconStyle != null){
_searchImgDisabled = disabledSearchIconStyle;
}

if(!isNaN(inputCodeWidthStyle)){
_inputCodeWidth = inputCodeWidthStyle;
}
}

Neste método armazenamos o estilo recolhido pelo getStyle e testamos se ele existe antes de substituir aquela propriedade padrão, definida no primeiro passo. Aqui, se necessário, nós podemos chamar o invalidateDisplayList com alguma flag. Assim, no updateDisplayList, fazemos as construções necessárias. Por exemplo, a construção de um traço, via CSS: Verificamos se o usuário quer construir o traço (através de uma propriedade CSS). Caso positivo, setamos uma flag e chamamos o invalidateDisplayList. No updateDisplayList, verificamos esta flag e construímos o traço. A forma como construir o traço pode variar desde a simples utilização do HRule ou VRule até por meio do objeto graphics.

Fazendo uso destas definições e aplicando os conceitos de temas e CSS, discutidos no post anterior, a personalização de uma aplicação Flex torna-se bem fácil!

Boa semana!