SmallFBP: a Smalltalk framework for Flow-Based Programming – Part 4

filter

Ciência, arte e filosofia se vão fundindo tanto em mim que algum dia certamente vou parir um centauro – Nietzsche.

  1.  Introdução
  2. Flow-Base Programming
    1. Component
    2. Port
    3. Information Packet (IP)
    4. Connection
    5. Network
    6. Initial Information Packet (IIP)
  3. Exemplo: Filter
    1. Introdução
    2. OddFilter
    3. Numbers
    4. MaxNumberIIP
    5. Printer
    6. Dropper
    7. Filter GUI
  4. Portas automáticas
    1. Introdução
    2. Exemplo: Writer e Reader
    3. Usando displays com portas automáticas
    4. Usando portas automáticas no exemplo Filter
  5. Componentes compostos
    1. Introdução
    2. Subnet
    3. Composição
  6. Flow-Based Programming IDE
    1. Introdução
    2. Arquitetura
    3. Protótipo
  7. Flow-Based Programming IDE II
    1. Introdução
    2. Odd filter
  8. Flow-Based Programming IDE – III
    1. Introdução
    2. Writer e Reader

Portas automáticas

Introdução

As portas automáticas são portas sem identificador que servem para troca de sinais entre componentes com o objetivo de sincronização. O projetista de rede pode conectar uma porta (automática) de saída em uma porta de entrada (automática) de outro componente. O componente que detém a porta de upstream da conexão coloca um pacote (sinal) na sua porta de saída automática. Para isto o método run deve terminar (não deve conter um laço infinito). Este envio do sinal não é programado pelo codificador do componente. É automático desde que o método run termine. O componente que detém a porta de downstream da conexão fica em suspenso até que receba um sinal na sua porta automática de entrada. Mas uma conexão pode ter de nenhuma a duas portas automática. Uma porta automática de saída pode estar conectada a uma porta de entrada comum e uma porta de saída comum pode estar conectada a uma porta de entrada automática. As portas automáticas são conectadas opcionalmente. Todos os componentes tem portas automáticas. Uma de entrada e outra de saída. Se a porta de entrada estiver conectada o componente fica com o processo suspenso até que receba um pacote (um sinal) nesta porta. Se o componente termina a execução do método #run e sua porta automática de saída está conectada um pacote (um sinal) é enviado para ela.

Exemplo: Writer e Reader

writer-reader-with-automatic-port

A rede do diagrama acima é configurada no código abaixo:

network-writer-reader

A linha dentro do retângulo em vermelho é uma nova mensagem para conectar portas automáticas. Como as portas automáticas não tem nome basta passar como argumentos os componentes upstream (Writer) e downstream (Reader). A porta automática de saída do componente upstream é conectada à porta de entrada do componente downstream. O código do método FBPNetwork>>#connect:to:  que responde à mensagem segue abaixo:

network-connect-to

Dois métodos (também novos) de FBPComponent são usados:

component-add-automatic-output-port

component-add-automatic-input-port

Vamos abordar cada componente da esquerda para a direita.

TextEditor

FBPTextEditor representa a interface gráfica do usuário. Usa uma GUI construída com Spec através de uma instância da classe FBPTextEditorWindow (uma humble interface).

Abaixo segue o método #run de FBPTextEditor:

text-editor-run

Na linha 3 a interface do usuário é instanciada e exibida (Veja a imagem abaixo).

gui-text-editor-window

Na linha 5 é configurado o texto que aparece num balão de ajuda quando há o hover do mouse sobre a área onde o texto é editado.

Da linha 7 em diante está o código que registra um listener (callback) que será invocado quando o menu de salvamento do arquivo ou o ícone da barra de menu for selecionado. Antes de salvar o texto no arquivo é preciso usar as teclas Cmd-S para informar que se terminou a edição do texto.

Na linha 8 o texto é obtido da interface.

A linha 9 testa se o texto é uma string vazia.

As linhas de 10 a 14 só são executadas se o texto não for vazio.

Na linha 10 é acrescentada mais uma linha ao texto obtido e que contém a string ‘__EOT__’ (que servirá de flag indicando o fim do texto).

Na linha 11 é dado um feedback ao usuário através de uma mensagem que aparece flutuando na tela e desaparece aos poucos.

Na linha 12 um pacote é criado com o texto.

Na linha 13 o pacote é enviado para a porta #TEXT.

Na linha 14 o menu e o ícone de salvamento do arquivo são desabilitados.

Note que não há laço no método.

Abaixo colocamos o file out da classe FBPTextEditorWindow que implementa a interface usando Spec:

'From Pharo3.0 of 18 March 2013 [Latest update: #30848] on 6 July 2014 at 2:29:24.44979 pm'!
ApplicationWithToolbar subclass: #FBPTextEditorWindow
instanceVariableNames: 'saveFileHandler saveFileSubmenu saveFileBarMenu'
classVariableNames: ''
poolDictionaries: ''
category: 'FlowBasedProgramming-Examples-WriterReader'!
!FBPTextEditorWindow commentStamp: '<historical>' prior: 0!
!

!FBPTextEditorWindow methodsFor: 'initialization' stamp: 'chicoary 7/4/2014 15:27'!
subMenu

^ MenuModel new
addGroup: [ :group |
group addItem: [ :item |
item
name: 'Save';
icon: Smalltalk ui icons smallSaveIcon;
shortcut: $s command;
action: [ self inform: 'Save'.
self handleSaveFile
].
saveFileSubmenu := item
].
group addItem: [ :item |
item
name: 'Kill';
shortcut: $k command;
icon: Smalltalk ui icons smallCancelIcon;
action: [ self inform: 'Kill' ] ] ]! !

!FBPTextEditorWindow methodsFor: 'initialization' stamp: 'chicoary 7/4/2014 15:27'!
initializeWidgets

menu := MenuModel new
addGroup: [ :group |
group addItem: [ :item |
item
name: 'File';
icon: Smalltalk ui icons openIcon;
subMenu: self subMenu].
group addItem: [ :item |
item
name: nil;
description: 'Save File';
icon: Smalltalk ui icons smallSaveIcon;
action: [ self inform: 'Save'.
self handleSaveFile
].
saveFileBarMenu := item
].
].

menu applyTo: self.
text := self newText.
self focusOrder add: text! !

!FBPTextEditorWindow methodsFor: 'as yet unclassified' stamp: 'chicoary 7/4/2014 15:29'!
disableSaveFileMenu
saveFileSubmenu enabled: false.
saveFileBarMenu enabled: false! !

!FBPTextEditorWindow methodsFor: 'as yet unclassified' stamp: 'chicoary 7/5/2014 18:34'!
textHelp: aString
text help: aString! !

!FBPTextEditorWindow methodsFor: 'as yet unclassified' stamp: 'chicoary 7/6/2014 13:29'!
getEditorText
^ self text getText string! !

!FBPTextEditorWindow methodsFor: 'as yet unclassified' stamp: 'chicoary 7/4/2014 13:39'!
whenSaveFileDo: aBlockClosure
saveFileHandler := aBlockClosure! !

!FBPTextEditorWindow methodsFor: 'as yet unclassified' stamp: 'chicoary 7/4/2014 13:42'!
handleSaveFile
saveFileHandler value! !

LineBreaker

FBPLineBreaker é a classe cujas instâncias são componentes que recebem um texto com várias linhas num pacote que é recebido na porta #TEXT e colocam cada linha num pacote separado que são consecutivamente enviados para a porta #LINE.

O código de #run segue abaixo:

line-breaker-run

Na linha 4 o pacote é recebido da porta #TEXT.

Na linha 5 o texto é obtido do pacote.

Na linha 6 o pacote é descartado.

Na linha 7 o texto é “quebrado” em várias linhas.

As linhas de 8 em diante representam um laço que percorre cada linha.

Na linha 9 é criado um pacote com a string da linha de texto.

Na linha 10 o pacote é enviado para a porta #LINE.

Writer

Writer recebe uma sequência de pacotes contendo strings da porta #LINE. As strings contidas nos pacotes são interpretadas como linhas a serem gravadas num arquivo. O nome do arquivo é recebido através da porta de configuração #FILE_NAME.

O código de #run segue abaixo:

writer-run

Na linha 4 um pacote é recebido da porta #LINE.

Na linha 5 o nome do arquivo é obtido do pacote.

Na linha 6 o pacote é descartado.

Na linha 7 o arquivo, se existir, é aberto para escrita. Se não existir é criado e aberto.

O laço da linha 8 a 14 executa enquanto não for lida a última linha.

Na linha 9 é acrescentada um caractere de  “quebra de linha” no final da linha.

Na linha 10 a linha é gravada no arquivo.

As linhas 11, 12 e 13 recebem um novo pacote da porta #LINE, obtém seu conteúdo e descartam o pacote.

As linhas 16 a 19 garantem, mesmo havendo um erro no bloco precedente, que o arquivo seja fechado.

Reader

Um componente que é instância de FBPReader faz o contrário de um componente FBPWriter. Lê um arquivo de texto do disco e envia para a saída.

Abaixo o código do #run:

reader-run

As linhas 4, 5 e 6  obtém o nome do arquivo a ser lido da porta #FILE_NAME.

Na linha 7 o conteúdo do arquivo é todo lido.

Na linha 8 o pacote contendo o texto do arquivo é enviado para a porta #TEXT.

As linhas de 9 a 11 garantem o fechamento do arquivo.

Transcripter

Um componente FBPTranscripter mostra uma string que representa o conteúdo de um pacote para cada pacote recebido na sua porta de entrada.

Este é o único componente da rede que é de fluxo contínuo (Tem um laço infinito). Todos os outros componentes tem seus processos terminados.

Abaixo mostramos as imagens das interfaces do usuário:

writer-reader-gui-before

writer-reader-gui-after

Nota: Um idioma comum quando se quer obter o conteúdo de um pacote e depois descartá-lo é o seguinte:

| packet content |
...
packet := self receiveFrom: #IN.
content := packet content.
self dropPacket: packet.
...

O código abaixo é equivalente mas apresenta um problema:

| packet content |
...
packet := (packet := self receiveFrom: #IN) content.
self dropPacket: packet.
...

Se a fila que representa a conexão entrante estiver vazia o processo/thread será suspenso e neste caso a expressão (packet := self receiveFrom: #IN) retorna um SmallInteger que não responde à mensagem #content, causando um erro.

Usando displays com portas automáticas

No exemplo anterior vamos incluir um display para mostrar o tráfego de pacotes na conexão entre as portas automáticas.

writer-reader-with-automatic-port-with-display

O código abaixo configura a rede.

network-writer-reader-with-display

A linha dentro do retângulo vermelho insere o display na conexão.

A execução da rede faz com que as seguintes janelas sejam exibidas:

network-writer-reader-with-display-UI

O código do novo método usado para inserir um componente de interceptação na conexão entre as duas portas automáticas segue abaixo:

network-connect-to-via

O método acima usa dois novos métodos: o primeiro para conectar uma porta de saída automática a uma porta de entrada comum e o segundo para conectar uma porta comum a uma porta automática.

Abaixo segue o código dos dois métodos:

network-connect-to-port-of

network-connect-port-to

Usando portas automáticas no exemplo Filter

filter-gui

Vamos alterar a rede acima para que a porta START de Numbers seja uma porta automática de entrada.

filter-gui-with-automatic-port

Agora temos um caso de uma porta de saída não-automática START do componente FilterGUI conectada a uma porta automática do componente Number. Isto permite que o componente FilterGUI controle o momento de início da atividade do componente Numbers.

O código de configuração da rede segue abaixo:

network-config-filter-gui-with-automatic-port

A linha contida no retângulo em vermelho conecta uma porta comum de saída na porta automática do gerador de números. O processo/thread do componente gerador de números permanece suspenso até que um pacotes chegue na sua porta automática.

Abaixo segue o código do método run do componente que gera os números inteiros aleatórios:

numbers-run-with-automatic-port

O código abaixo é o antigo usando uma porta comum (START):

numbers-run-without-automatic-port

A linha no retângulo vermelho foi removida no método run do componente que passou a usar a porta de entrada automática para controlar o momento da execução do método run.

O novo método #start para lidar com as portas automáticas segue abaixo:

component-start-with-automatic-ports

A invocação do método #run agora está num “sanduíche” que trata as portas automáticas. Desta forma o componente só inicia a execução do código em #run quando um pacote é recebido na sua porta automática. Enquanto isto o processo fica em estado suspenso (Não consome ciclos de CPU). Se o método #run termina, antes que o processo termine e saia definitivamente do processador, é enviado um sinal para a sua porta automática de saída. Se as portas automáticas não estiverem conectadas elas são ignoradas.

O código dos métodos para processar as portas automáticas seguem abaixo:

component-processAutomaticInput

component-processAutomaticOutput

Anúncios

7 Respostas para “SmallFBP: a Smalltalk framework for Flow-Based Programming – Part 4

  1. Pingback: SmallFBP: a Smalltalk framework for Flow-Based Programming | Crab Log

  2. Pingback: SmallFBP: a Smalltalk framework for Flow-Based Programming – Part 2 | Crab Log

  3. Pingback: SmallFBP: a Smalltalk framework for Flow-Based Programming – Part 3 | Crab Log

  4. Pingback: SmallFBP: a Smalltalk framework for Flow-Based Programming – Part 5 | Crab Log

  5. Pingback: SmallFBP: a Smalltalk framework for Flow-Based Programming – Part 6 | Crab Log

  6. Pingback: SmallFBP: a Smalltalk framework for Flow-Based Programming – Part 7 | Crab Log

  7. Pingback: SmallFBP: a Smalltalk framework for Flow-Based Programming – Part 8 | Crab Log

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s