Livro completo - Departamento de Informática e Estatística

Transcrição

Livro completo - Departamento de Informática e Estatística
ERCEMAPI 2011
V Escola Regional de Informática
Ceará – Maranhão – Piauí
Teresina, 07 e 08 de novembro de 2011
LIVRO TEXTO DOS MINICURSOS
Edição
Sociedade Brasileira de Computação
Organizadores
André Macêdo Santana
Pedro de Alcântara dos Santos Neto
Raimundo Santos Moura
Promoção
Sociedade Brasileira de Computação
Patrocínio
Realização
Universidade Federal do Piauí
Instituto Federal de Educação, Ciência e Tecnologia do Piauí
Apoio
Fundação de Amparo a Pesquisa do Estado do Piauí
Copyright Sociedade Brasileira de Computação
Todos os direitos reservados
i
Escola Regional de Informática Ceará, Maranhão, Piauí
(2011: Teresina, PI)
Escola Regional de Informática Ceará, Maranhão, Piauí: Livro texto
dos minicursos, 07 e 08 de novembro de 2011. [livro eletrônico] /
organizadores, André Macêdo Santana, Pedro de Alcântara dos Santos Neto,
Raimundo Santos Moura. – Teresina: Sociedade Brasileira de Computação –
SBC, 2011.
200p. : il. ; livro eletrônico.
Realização: Universidade Federal do Piauí - UFPI.
Promoção: Sociedade Brasileira de Computação – SBC.
ISBN 978-85-7669-258-4.
1. Computação; Ciência da Computação; I. Santana, André Macêdo.
II. Santos Neto, Pedro de Alcântara dos. III. Moura, Raimundo Santos
IV. Título.
CDD 004.1
ii
ERCEMAPI 2011
PREFÁCIO
Em 2007, quando da primeira edição da Escola Regional de Informática Ceará Maranhão - Piauí (ERCEMAPI) houve muitos questionamentos sobre a continuidade
dessa ideia, que foi inicialmente encabeçada por um grupo cearense. Sua segunda
edição (2008), no estado do Maranhão, foi bastante tímida e os questionamentos
continuaram. Em 2009, tivemos a consolidação do evento, com uma participação
maciça de estudantes do Piauí, Ceará e Maranhão, além de estudantes de outros
estados. O evento foi pela primeira vez organizado fora das capitais dos estados e
mostrou que a ideia de sua realização era totalmente válida e bem aceita pela
comunidade acadêmica dos estados pertencentes à então regional Nordeste 3.
Agora em 2011, na sua quinta edição, o Piauí teve a honra de sediar o evento
mais uma vez. Houve uma inversão na ordem de organização, entre Piauí e Maranhão,
à pedido dos representantes maranhenses. A responsabilidade de organização neste
ano era, maior ainda, dado o sucesso da edição anterior realizada em Sobral-CE.
No entanto, mais uma vez conseguimos superar todas as expectativas e realizar
um evento memorável, que só estimula a sua ampliação. Houve cerca de 500
participantes nesta edição, um recorde muito difícil de ser batido! Geramos um grande
“problema“ aos nossos colegas maranhenses, que terão que trabalhar bastante para
tentar manter o ritmo crescente do evento. Certamente teremos a dedicação dos
nossos vizinho nessa tarefa, além do nosso apoio incondicional ao que for necessário
para tal realização.
O grande sucesso da edição 2011 deveu-se à realização conjunta do evento
com um evento tradicional no estado, o Simpósio Piauiense de Informática (InfoPI),
bem como a realização da Escola de Microeletrônica do Piauí e da Escola de Sistemas
Embarcados do Piuaí. Foi uma avalanche de conhecimento concentrada em uma
semana inteira de palestras, minicursos e apresentações de trabalho.
iii
O objetivo inicial do evento, quando criado em 2007, era de aproximar os
estados vizinhos nas atividades de ensino e pesquisa. Neste ano, pudemos notar que o
objetivo inicial foi alcançado. Atualmente existem orientações de trabalhos de
mestrado em conjunto, participação em bancas e desenvolvimento de artigos. Tudo
isso fruto da aproximação propiciada por esse evento, que já faz parte do calendário
acadêmico dos três estados. Sua força é tanta que, mesmo com a criação de uma
regional da SBC específica para o estado do Ceará, continuaremos juntos nas próximas
edições do ERCEMAPI.
É com esse espírito que gostaríamos de expressar nosso agradecimento a todos
os que contribuíram para tornar a ERCEMAPI um evento de tanto sucesso. Próximo
ano estaremos na "terra das palmeiras” para fincar a bandeira do ERCEMAPI em
definitivo também nesse estado. Que venha a edição de 2012!
Teresina, novembro de 2011
André Macêdo Santana
Pedro de Alcântara dos Santos Neto
Raimundo Santos Moura
iv
ERCEMAPI 2011
V Escola Regional de Informática – Ceará – Maranhão – Piauí
COMISSÃO ORGANIZADORA
Coordenador Geral:
Raimundo Santos Moura
Coordenação do Comitê de Programa:
André Macêdo Santana
Comissão Científica:
André Castelo Branco Soares
Erick Baptista Passos
Ivan Saraiva Silva
Comissão Financeira:
Fabio de Jesus Lima Gomes
Kelson Rômulo Teixeira Aires
Comissão de Marketing e Divulgação:
Adalton de Sena Almeida
Harilton da Silva Araújo
Joselé Martins
Pedro de Alcântara dos Santos Neto
Vinicius Ponte Machado
Comissão de Infra-Estrutura:
Eduilson Lívio Neves da Costa Carneiro
Rodrigo de Melo Sousa Veras
v
ERCEMAPI 2011
SUMÁRIO
Capítulo 01
Linhas de produto de software: Uma tendência da indústria
07
Airton Silva (UFPE), Paulo Anselmo (UFPE), Vinicius Garcia (UFPE) e Patrícia Muniz (RISE)
Capítulo 02
Planejamento de capacidade de sistemas através de Cadeias de Markov
32
Rubens de Souza Matos Júnior (UFPE), Carlos Julian Araújo (UFPE), Franscico de Souza
(UFPI) e Paulo Maciel (UFPE)
Capítulo 03
Computação autônomica aplicada a segurança de redes
54
Ariel Teles (UFMA), Francisco José Silva (UFMA) e Zair Abdelouahab (UFMA)
Capítulo 04
Linked Data: da Web de documentos para a web de dados
79
Bernadette Lóscio (UFPE), Danusa Ribeiro Bezerra da Cunha (UFCE) e Damires Sousa (IFPB)
Capítulo 05
Desenvolvimento de Aplicações para Plataforma Google Android
100
Fabio de Jesus Lima Gomes (IFPI), Manoel Taenan (IFPI) e Rafael Lins (IFPI)
Capítulo 06
Desenvolvendo aplicações multi-tenancy para computação em nuvem
124
Josino Neto (UFPE), Vinicius Garcia (UFPE) e Wilton Oliveira Ferreira (UFPE)
Capítulo 07
Introdução a agentes autônomos e sistemas multiagentes
141
Samy Sá (UFCE), João Alcântara (UFCE) e Marcos de Oliveira (UFCE)
Capítulo 08
Desevolvimento para dispositivos móveis que utilizar a plataforma iOS
166
Ricardo Freitas (UFPI), Roniel Soares (UFPI), José Almi Soares Filho (UFPI),
Kelson Aires (UFPI), André Soares (UFPI), Vinicius Machado (UFPI), Laurindo Neto (UFPI)
Capítulo 09
Desenvolvimento de aplicações móveis utilizando a linguagem declarativa QML
191
Ricardo Erikson (UFAM), Adriano Gil (UFAM), Paulo Mendonça (UFAM),
Cícero Costa Filho (UFAM) e Vicente Lucena (UFAM)
Capítulo 10
Técnicas de Processamento de imagens em diagnóstico auxiliado por
computador
Rodrigo Veras (UFPI), Iális Paula Jr (UFCE) e Fátima Medeiros (UFCE)
vi
216
Capítulo
1
Linhas de Produtos de Software: Uma tendência
da indústria
Francisco Airton Pereira da Silva, Paulo Anselmo da Mota Silveira Neto,
Vinicius Cardoso Garcia e Patrícia Fontinele Muniz
Abstract
Over the past few years a new approach to software reuse has gained attention both by industry and academia. This approach is known as software product line development wich
is based upon the systematic reuse of software artifacts, through exploiting commonalities
and managing variabilities among products, that are established under a common architecture. This concept of product lines have been used by the manufacturing industry for
a long time to reduce costs and increase productivity. However, product line practice in
the software industry is a relatively new concept. Studies have shown that organizations
can yield remarkable improvements mainly in productivity by applying this approach. In
this context, this chapter presents some of the most important aspects related to software
product lines, such as variability, development processes and finally presents some tools
to support Software Product Line (SPL).
Resumo
Ao longo dos últimos anos uma nova abordagem de reuso de software tem ganhado atenção tanto pela indústria quanto pela academia. Esta abordagem é conhecida como Linhas de Produtos de Software na qual é baseada na reutilização sistemática de artefatos
de software, através da exploração de pontos comuns e a gestão de variabilidade entre os
produtos, que são estabelecidos sob uma mesma arquitetura. Este conceito de linhas de
produtos tem sido utilizado pela indústria de manufatura a anos para reduzir custos e aumentar a produtividade. No entanto esta prática possui um conceito relativamente novo
na indústria de software. Estudos têm demonstrado que as organizações têm apresentado
melhorias principalmente na produtividade aplicando esta abordagem. Neste contexto,
este trabalho apresenta alguns dos aspectos mais importantes sobre linhas de produtos de
software, tais como variabilidade, processos de desenvolvimento e finalmente mostrando
algumas ferramentas de apoio a Linhas de Produtos de Software (LPS).
7
1.1. INTRODUÇÃO
A maneira que os bens de consumo são produzidos mudou significativamente no decorrer
do tempo. Anteriormente mercadorias eram especificas para clientes individuais. Cada
vez mais, o número de pessoas que poderiam ter recursos para comprar vários tipos de
produto foi aumentando. No domínio dos automóveis, isso levou à invenção por Henry
Ford da linha de produção, o que permitiu a produção para um mercado de massa muito
mais barata do que a criação de cada produto em uma base artesanal. No entanto, a linha
de produção reduziu as possibilidades de diversificação.
A grosso modo, ambos os tipos de produtos, individual e os produzidos em massa
também podem ser identificados no domínio de software: eles são denominados como
software individual e software padrão. Geralmente, cada um destes tipos de produtos tem
suas desvantagens. Produtos de software individuais são bastante caros pois exigem um
maior esforço desenvolvendo espeficidades de um único produto, enquanto produtos de
software padrão (sem muita especificidade) existe a falta de diversificação suficiente para
atender bem às expectativas de muitos clientes diferentes.
No início os clientes estavam satisfeitos com os produtos padronizados em massa
por um tempo, mas nem todas as pessoas queriam o mesmo tipo de carro para qualquer
finalidade. Certos carros são usados para viajar por uma única pessoa, outros por grandes
famílias por exemplo. Assim, a indústria foi confrontada com uma crescente demanda
por produtos individualizados. Este foi o início da chamada customização em massa, o
que significava atender às exigências dos clientes dando-lhes o que eles queriam.
Para o cliente a customização em massa significa a capacidade de ter um produto
individualizado, no entanto para a indústria significa maiores investimentos em tecnologia
que elevam os preços de produtos individualizados e / ou menores margens de lucro para
a empresa. Ambos os efeitos são indesejáveis. Assim, muitas empresas, especialmente
na indústria automobilística, começaram a apresentar plataformas comuns para os seus
diferentes tipos de carros planejando de antemão quais peças seriam usadas em vários
tipos de carros diferentes.
Ao longo do tempo a plataforma foi sendo trabalhada a fim de se tornar cada
vez mais adaptável a novos componentes. As partes compreendendo a plataforma eram
geralmente mais caras em termos do projeto e os custos de preparação de fabricação.
Porém esta estratégia levou a uma redução no custo de produção para um tipo de carro
particular [21].
A indústria de automóveis passou por esta transformação na forma de produzir
seus produtos e a indústria de software também necessita atender ao mesmo requisito de
individualidade e cada vez mais produção em massa. O mercado de desenvolvimento de
software precisa construir os produtos de software com melhor qualidade, redução de custos, adaptação rápida às mudanças, e menor tempo de colocação no mercado atendendo às
necessidades dos clientes. Visando estas expectativas vários esforços em criar processos
e arquituras de sistemas tem sido realizadas ao longo dos anos [16].
Seguindo por este caminho uma nova abordagem para reutilização de software
tem ganhado considerável atenção tanto pela indústria quanto pela academia. Esta abordagem é conhecida como Linha de Produtos de Software (LPS) onde a idéia básica é o
8
trabalho sobre um grupo de sistemas compartilhando um conjunto comum e gerenciado
de funcionalidades (features) que satisfazem necessidades específicas de um segmento, e
desenvolvidos a partir de um aglomerado comum de artefatos base e de forma previamente
planejada. Em outras palavras LPS faz uso da reusabilidade para construir sistemas com
menos esforço desde que estes pertençam a uma mesma família, ou seja, que possuam
pontos em comum [17].
Este capítulo está organizado como segue: na seção 1.2 será apresentada uma visão geral sobre as peculiaridades sobre Linhas de Produtos de Software, incluindo idéias
comparativas entre estas metodologias e o reuso de software tradicional. Na seção 1.3
como as variantes de um produto podem ser gerenciadas. Na seção 1.4 atividades exercidas no desenvolvimento de LPS, mostrando algumas ferramentas. Finalmente na seção
1.5 são apresentadas as conclusões.
1.2. VISÃO GERAL SOBRE LINHAS DE PRODUTOS DE SOFTWARE
Os artefatos mencionados na seção anterior devem ser reutilizados de uma forma consistente e sistemática, a fim de construir aplicativos robustos em LPS. Artefatos reutilizáveis
abrangem todos os tipos de artefatos de desenvolvimento de software, tais como modelos
de requisitos, modelos de arquitetura, componentes de software e planos de teste.
A experiência de projetos que fazem uso de reutilização na década de 1990 mostraram que, sem planejamento adequado, os custos do projeto com reutilização pode ser
maior do que para desenvolver os artefatos a partir do zero. Assim, é fundamental planejar
com antecedência os produtos para os quais a reutilização será aplicada, juntamente com
as features que caracterizam estes produtos. O planejamento para reutilização continua
durante todo o processo de desenvolvimento [21].
Para facilitar a customização em massa a plataforma deve fornecer os meios para
satisfazer as necessidades dos diferentes stakeholders. Para este propósito, o conceito
de variabilidade foi criado, para explorar as características que variam em relação aos
diversos produtos. Como conseqüência de aplicar este conceito, os artefatos que podem
serem diferentes nas aplicações da linha de produtos são modelados usando variabilidade
[21].
1.2.1. Processos de Desenvolvimento
O paradigma de linha de produtos de software é dividido em dois processos, a saber:
1. Engenharia de Domínio: Este processo é responsável por estabelecer a plataforma
de reutilização e, assim definir comunalidade e a variabilidade da linha de produtos.
A plataforma consiste em todos as tipos de artefatos de software (requisitos, design,
testes, etc.) também chamados de ativos base.
2. Engenharia de Aplicação: Este processo é responsável por derivar aplicações concretas a partir da plataforma estabelecida na engenharia de domínio. Ela explora a
variabilidade da linha de produtos e assegura sua correta instanciação de acordo
com as necessidades específicas das aplicações finais.
9
Figura 1.1. Dois ciclos de vida que separam engenharia de domínio e aplicação.
A vantagem dessa divisão é que há uma separação de objetivos, para construir uma
plataforma robusta e para construir aplicações específicas em um curto espaço de tempo.
Para ser eficaz, os dois processos devem interagir de uma maneira que seja benéfica para
ambos.
A Figura 1.1 mostra como estes processos interagem entre si e qual o resultado dos
mesmos através de um fluxo de informações. Tanto na engenharia de domínio quanto na
engenharia de aplicação são realizadas atividades de análise, arquitetura, implementação
e testes para ao final serem gerados os produtos.
1.2.2. Linha de Produtos de Software e Reuso de Software Tradicional
Desenvolvimento de uma LPS envolve "reuso"e a primeira vista este desenvolvimento
pode parecer apenas um reuso de software tradicional. No entanto desenvolvimento de
uma linha de produtos de software é muito mais elaborado do que a reutilização de software tradicional. No reuso de software tradicional, as organizações possuem repositórios
onde a saída de praticamente todo o esforço de desenvolvimento é armazenado. Este repositório normalmente contêm alguma biblioteca de reutilização de componentes, módulos
e algoritmos que desenvolvedores são incentivados a usar. O problema com este tipo de
reutilização é que, geralmente, leva mais tempo para encontrar a funcionalidade desejada
e adaptá-la à aplicação atual do que para construí-la novamente [7].
Este tipo de reutilização ad hoc não é o que caracteriza o desenvolvimento de
linhas de produtos de software. Em desenvolvimento de linhas de produtos o reuso é
planejado, automatizado e sistemático [20]. O "repositório de reuso"de uma linha de
10
produtos de software é conhecido como ativos base. Estes elementos incluem todos os
artefatos que são os mais caros para desenvolver como modelos de domínio, requisitos,
arquitetura, componentes, casos de teste, etc.
Além disso, esses ativos são do início do desenvolvido a fim de serem reutilizados
em vários produtos. Isto significa que a customização de ativos para o produto atual, normalmente não inclue nenhum código novo como ocorreria em abordagens tradicionais.
Ao invés disto ocorre uma instanciação do produto, utilizando mecanismos de variabilidade incorporadas aos ativos base.
Outra abordagem para reutilização de software que se assemelha a de desenvolvimento de software em linhas de produtos é conhecido como a abordagem "clone and
own"[20]. Os produtos desenvolvidos por esta abordagem tem um foco no produto individual, não ocorre um foco na família de produtos de software, e portanto, não implementa
os mecanismos de variabilidade que caracterizam o desenvolvimento da família de produtos.
Portanto quando um projeto novo é iniciado por esta abordagem, a equipe de desenvolvimento tenta encontrar um outro produto dentro da organização que se assemelha o
produto atual, tanto quanto possível. Eles, então, copiam tudo o que podem a partir desse
projeto, modificam e adicionam o que é necessario para lançar o novo produto. Esta abordagem pode render uma economia considerável em comparação com desenvolvimento de
todos os produtos a partir do zero. No entanto, ao comparar o "clone and own"com a
abordagem de desenvolvimento de linha de produtos, o "clone and own"apresenta algumas desvantagens principais:
1. No desenvolvimento de linha de produtos todos os artefatos de maiores custos do
projeto são reutilizados, não apenas o código que é o foco principal da abordagem
"clone and own".
2. No desenvolvimento de linha de produtos todos os ativos base são desenvolvidos
tendo em mente a idéia de reutilização e variabilidade. Na abordagem "clone and
own", tudo é desenvolvido com foco no produto individual, onde os recursos não
serão gastos no desenvolvimento de mecanismos de variabilidade que não serão
usados por este produto. Isto implica que o "clone"exigirá um esforço considerável de customização para atender os requisitos do novo produto comparado a outro
dentro de uma linha de produtos. Os ativos base de uma linha de produtos provavelmente não irão precisar de um alto grau de customização para atender aos
requisitos de novos produtos, mas sim uma instanciação de mecanismos integrados
de variabilidade anteriormente construídos.
3. Quando "clonamos"um produto já existente, para criar um novo produto, as ligações entre estes projetos são inexistentes e futuramente ocorrerá manutenções individuais nos dois produtos. No caso do desenvolvimento de linha de produtos, uma
economia considerável pode ser realizada ao longo do ciclo de vida destes, pois
a manutenção dos ativos base é uma responsabilidade compartilhada por todos os
produtos na família.
11
1.2.3. Aspectos importantes na adoção de Linhas de Produtos de Software
A adoção de linhas de produtos de software é diferente em alguns sentidos em relação a
adopção de outros tipos de tecnologias e processos. Sua adoção requer bastante tempo,
principalmente em estágios iniciais [17]. Isso envolve a mudança na forma de desenvolvimento de sistemas que possui a idéia de sistema único para o desenvolvimento de vários
produtos a partir de uma plataforma [19].
A adoção envolve ter uma base de ativos base, processos de suporte, e estruturas
organizacionais; desenvolver produtos a partir da base de ativos de uma forma que sejam
atingidos objetivos de negócio; e instituir mecanismos para melhorar e extender o esforço
de produção de software, desde que faça sentido. No entanto, dependendo do cenário,
atingir as metas de adoção pode tornar-se uma atividade complexa.
A fim de evitar complexidades adicionais durante a fase de adoção, Gary [8] argumenta que uma organização que pretende adotar uma abordagem de linha de produto deve
ter objetivos claros em mente. Para atingir seus objetivos, a organização seleciona um ou
mais estratégias de adoção que especificam como ele serão abraçadas as práticas de linhas
de produtos. Em seguida, um plano de adoção mostra em detalhes que atividades devem
ser realizadas para implementar essas estratégias.
Neste sentido, todo o conceito de adoção de linha de produtos se torna muito pessoal para a organização, o contexto específico parece desempenhar um papel significativo
na decisão de adoção [8]. Portanto, a transferência deve ser sistematicamente e planejada.
1.2.4. Vantagens em Linhas de Produtos de Software
Teorias relacionadas a linhas de produtos de software pode gerar diversos benefícios classificados em três tipos: benefícios organizacionais, os benefícios de engenharia de software e os benefícios de negócio.
Os benefícios organizacionais agrupam vantagens como uma melhor compreensão do domínio, a maior facilidade de treinar pessoas, um produto de maior qualidade e
consequentemente confiança do cliente.
Os benefícios da engenharia de software incluem vantagens como a reutilização
de requisitos e seus componentes, uma melhor análise de requisitos, uma outra visão
sobre os requisitos para o cliente, controle de qualidade de software, estabelecimento de
padrões de programação.
E por último mas não menos importante, benefícios comerciais dizem respeito
à redução de manu-tenção e custos de teste (graças à reutilização entre vários produtos
semelhantes). Além disso, as linhas de produtos geram uma melhor eficiência nos processos e a possibilidade de aumentar o orçamento e melhorar o planejamento do tempo
por ter maior controle dos componentes que fazem parte do produto final. Uma descrição
detalhada dos benefícios pode ser encontrada na seção "benefícios e custos da linha de
produtos"em [6].
Várias estatísticas concretas são apresentados para ilustrar as melhorias de custos,
tempo de mercado e produtividade [15].
12
1. Nokia é capaz de produzir 25-30 modelos diferentes de celular por ano por causa
da abordagem de linha de produtos.
2. Cummins, Inc., foi capaz de reduzir o tempo que leva para produzir o software de
um motor diesel de cerca de um ano para cerca de uma semana.
3. Motorola observou uma melhoria de produtividade de 400% em uma família de
determinado tipo de celular.
4. Hewlett-Packard reportou uma redução no time to market por um fator de sete e
um aumento na produtividade por um fator de seis, em uma família de sistemas de
impressoras.
1.2.5. Desvantagens em Linhas de Produtos de Software
Realizar uma mudança de um modo original de desenvolvimento de software em uma
organização do ponto de vista de um produto único para uma abordagem com linha de
produtos envolve uma mudança fundamental para a organização e para as mentalidades
que pode trazer o que chamamos de resistência a mudanças.
Outro problema está relacionado ao fato de poucos engenheiros de software terem uma visão global sobre toda a arquitetura de linha de produtos. Nos estudos de caso
apresentados em várias partes do livro [11], ele enfatiza a necessidade de um especialista na linha de produtos que sabe perfeitamente como funciona o domínio da aplicação,
que tem responsabilidade suficiente, autoridade, experiência dentro da empresa, que tem
motivação e compreensão sobre teorias em linhas de produtos de software.
Algumas dificuldades podem aparecer, quando uma decisão deve ser tomada para
mesclar ou não um novo produto com a linha de produtos. A evolução do domínio requer
cautela para fixar o alcance da linha de produtos. De fato, um escopo muito amplo torna
a manutenção de ativos base demasiadamente complexa para haver reutilização de forma
eficaz, e um escopo muito limitado não justifica o custo de desenvolvimento e manutenção
do núcleo dos ativos base.
Projetar arquiteturas de linha de produto muitas vezes se torna difícil, devido à
falta de diretrizes, representações maduras de como validar arquiteturas de referência e
ferramentas integradas para desenvolver e explorar as linhas de produtos de software.
Dado as dificuldades apresentadas, Sholom [11] lista alguns problemas diferentes com
base em um questionário, ressaltando que a resistência organizacional e de investimento
são os mais críticos dentre todos os problemas (Tabela 1.1).
Quando comparamos o desenvolvimento tradicional de software com o desenvolvimento a partir de linhas de produtos (Figure 1.2), podemos salientar que neste último
precisa-se de uma gestão a longo prazo, porque os benefícios visíveis não são imediatos.
De fato, nos primeiros estágios em LPS é necessário um investimento inicial considerável
onde o ponto de equilíbrio de investimento/retorno seria alcançado geralmente a médio
prazo. Um número suficiente de produtos devem ser desenvolvidos a fim de apreciar as
vantagens reais .
13
Tabela 1.1.
Riscos na
adoção de LPS [11]
Risco Porcentagem
Resistencia organizacional
52%
Resistência da gestão
36%
Resistência dos desenvolvedores
32%
Preocupações com grandes investimentos
45%
Falta de pessoal devidamente treinado
29%
Incapacidade de medir o impacto
19%
Preocupação com o tempo de um projeto
18%
Figura 1.2. Comparação de custos entre abordagem tradicional e LPS [11]
1.3. VARIABILIDADE
O conceito de variabilidade está relacionado às possibilidades de mudar ou personalizar
um sistema. A Figura 1.3 ilustra como a variabilidade de um sistema de software é limitada durante todo o projeto de construção do mesmo. No início a quantidade de sistemas
possíveis é grande pois as restrições são mínimas. Durante a execução do projeto na construção do sistema as possibilidades diminuem, até que finalmente em tempo de execução
existe exatamente um sistema apenas. Em cada etapa do desenvolvimento, decisões de
design são feitas. Cada decisão restringe o número de possíveis sistemas
Com a abordagem de LPS as variabilidades são modeladas na arquitectura de
referência da LPS (através da representação dos Pontos de Variabilidade e Variantes respectivos) e resolvidas antes da instalação dos produtos.
• Um Ponto de Variabilidade corresponde a um aspecto de variação funcional num
elemento de software base. O ponto de variabilidade define o conjunto de possíveis
variantes, o mecanismo de variabilidade a utilizar para os instanciar e o tempo de
ativação dos variantes, e.g. instanciação da arquitectura de software do produto,
tempo de compilação, execução.
14
• Um Variante corresponde a uma opção do conjunto de possíveis instâncias de variação que um ponto de variabilidade poderá originar.
Figura 1.3. Quantidade de produtos possíveis
Em geral há sempre um certo grau de variabilidade difícil de manter em LPS.
Reusabilidade e flexibilidade têm sido a força motriz por trás do desenvolvimento de
técnicas como orientação a objetos, frameworks orientados a objeto e LPS.
Os Pontos de Variabilidade podem ser apresentados em vários níveis de abstração
[4]:
• Descrição da Arquitetura. Tipicamente, o sistema é descrito usando uma combinação de documentos de alto nível de design, linguagens de descrição de arquitetura
e documentação textual.
• Documentação por Diagramas. A este nível o sistema pode ser descrito usando
várias notações UML.
• Código-Fonte. A este nível, uma descrição completa na forma de código-fonte é
criado.
• Código Compilado. O código fonte é convertido para o código compilado usando
um compilador. Os resultados desta compilação pode ser influenciada por meio de
directivas de pré-processamento para então o resultaodo ser combinado.
• Código Ligado. Durante a fase de ligação, os resultados da fase de compilação
são combinados. Isto pode ser feito estaticamente (em tempo de compilação) ou
dinamicamente (em tempo de execução).
15
• Código de Execução. Durante a execução, o sistema já construído é iniciado e
configurado. Ao contrário das representações anteriores, o sistema de execução é
dinâmico e muda o tempo todo.
1.3.1. Gerenciando Variabilidades
Ao desenvolver uma LPS, o objetivo final é torná-la flexível o suficiente para atender às
novas exigências. Os pontos de variabilidade mais importantes precisam ser identificados
antecipadamente, a fim de alcançar este objetivo. Acontece que muitas vezes é muito
difícil de adaptar uma arquitetura existente para suportar um certo ponto de variabilidade.
Segundo Muhammad [4] a gestão da variabilidade consiste nas seguintes tarefas:
• Identificando Variabilidades. Na fase inicial de desenvolvimento de uma LPS,
os desenvolvedores são confrontadas com uma série de requisitos. Eles devem de
alguma forma trabalhar sobre estes requisitos formando uma especificação mais
adequada para a LPS. O objetivo deste processo não é chegar a um especificação
completa da LPS, mas sim identificar a diferença entre os produtos (ou seja, onde
as "coisas"tendem a variar) e quais características são compartilhadas por todos os
produtos. Feature Models apresentam uma excelente forma de representar variabilidades.
• Introduzindo a variabilidade no sistema. Uma vez que a variabilidade foi identificada, o sistema deve ser projetado de tal forma que ela possa ser introduzida.
Existe uma ampla gama de mecanismos e técnicas para esta tarefa. O mecanismo
escolhido depende do nível em que a variabilidade é introduzida, o tempo que o
sistema será ligado a um variante particular e a forma como novas variantes (se
houver) serão adicionadas ao sistema.
• Agrupando as variantes. Esta fase resulta em um conjunto de variantes associadas
a um ponto de variabilidade. A coleção de variantes pode ser implícita ou explícita.
No caso da implícita o sistema baseia-se no conhecimento dos desenvolvedores ou
usuários para escolherem variantes adequadas quando assim for necessário. Uma
coleção explícita, por outro lado, implica que o sistema pode, por si só, decidir
qual variante usar. A coleção pode ser fechada, o que significa que nenhuma nova
variante pode ser adicionada, ou ela pode permanecer aberta para novas adições.
• Vinculando o sistema a uma variante. Resulta em um sistema onde um ponto de
variabilidade particular é associado a uma de suas variantes. Esta vinculação pode
ser feita internamente ou externamente, a partir da perspectiva de sistemas. Uma
ligação interna implica que o sistema possui a capacidade de vincular uma variante
particular, ao passo que se a ligação é realizada externamente, o sistema tem que
contar com outras ferramentas, como ferramentas de gerenciamento de configuração para executar a vinculação. Relacionando esta com o agrupamento de variantes,
vemos que a gestão de variabilidade pode ser implícita e externa, implícita e interna,
ou explícita e interna. A seleção de qual variante usar envolve escolher uma variante
dentre o conjunto de variantes.
16
1.3.2. Feature Model
Comunalidade e variabilidade entre produtos de uma linha pode ser expressa em termos
de features. O conceito de feature foi originalmente apresentado pelo método Feature
Oriented Domain Analysis (FODA). De acordo com este modelo uma feature é uma característica do sistema visível ao usuário final. Uma feature é definida como uma unidade
lógica de comportamento que é especificada por um conjunto de requisitos funcionais e
de qualidade. Além disso, o comportamento deve ser relevante para um ou vários stakeholders de um produto [7].
O conceito de feature simplifica o trabalho com os requisitos, porque ele pode
ser usado para agrupar um conjunto de requisitos relacionados. Em outras palavras, as
features são uma forma de abstrair os requisitos. É importante perceber que existe uma
relação n-para-n entre features e requisitos.
Por esta relação com os requisitos o conceito de feature pode também diminuir a
distância em termos de comunicação entre o usuário final e o desenvolvedor. Os usuários
podem reportar defeitos ou requisições de uma nova funcionalidade por meio de features e
desenvolvedores podem então reinterpretar esta representação transformando-a em ações
a serem aplicadas ao ciclo de vida da construção do produto [7].
Deste modo, á medida que reunimos em um gráfico, as features de um sistema
nós construímos um feature model. O feature model procura apresentar uma visão geral
de alto nível das principais características comuns e variáveis de uma linha de produtos.
1.3.3. Notação F.O.D.A
O método Feature Oriented Domain Analysis (FODA) foi desenvolvido no Software Engineering Institute para representar graficametne o feature model. Sua descrição detalhada
do processo de Análise de Domínio o fez tornar-se um dos métodos mais populares na
década de 1990. Em particular, FODA fez uma contribuição significativa para a popularidade atual da análise orientada a modelo: o uso de várias visões complementares de um
domínio para transmitir informações mais completas sobre ele [14].
A modelagem de features de maneira explícita é a chave para o método FODA, e
é base para muitos dos trabalhos posteriores. FODA se posiciona como parte integrante
da engenharia de domínio a fim de facilitar a engenharia de aplicação.
O feature model foi introduzido como parte do método FODA, e representa uma
hierarquia de propriedades de conceitos do domínio. É uma das técnicas mais bem sucedidas para facilitar a reutilização de artefactos de software. O feature model é uma
representação hierárquica, que visa captar os relacionamentos estruturais entre as features
de um domínio de aplicação. O modelo também representa as features comuns e variáveis de instâncias de conceitos (por exemplo, sistemas de software) e dependências entre
as features variáveis. Um feature model consiste em um diagrama composto de features
e alguma informação adicional, tais como descrições semânticas de cada feature, pontos
variáveis, prioridades e regras de dependência.
No contexto das linhas de produto de software, um feature model representa a
própria linha de produtos. Uma feature pode ser de um dos seguintes tipos:
17
• Obrigatória: A feature tem de estar presente em todos os membros da linha de
produtos.
• Opcional: A feature pode ou não estar presente em um membro da linha de produtos.
• Alternativa: É uma feature que é composta de um conjunto de features das quais
se escolhe uma ou mais, devendo-se indicar se é necessário escolher apenas uma
ou se se pode escolher mais que uma. Nestas features é necessário fazer a distinção
de alternativas OR, que permite mais do que uma feature, e XOR, que mostra a
exclusão mútua.
Uma feature obrigatória é representada por uma aresta terminada por um círculo
preenchido a preto. Uma feature opcional é representada por uma aresta terminada por um
círculo vazio. As features alternativas são representadas por arestas que estão ligadas e
conectadas por um arco. Se o arco for vazio deve-se escolher apenas uma das alternativas
(XOR), se for preenchido é permitido escolher mais de uma alternativa (OR) [23].
Czarnecki [13] propõe colocar cardinalidade nas features para poder remover ambiguidades e representar a informação mais facilmente, sendo as diferentes cardinalidades
assim definidas:
• 0..1 Pode-se escolher uma ou nenhuma feature do conjunto de sub-features.
• 1 Exatamente uma feature tem de ser escolhida de um conjunto de sub-features.
• 0..* Um número arbitrário de features (ou nenhuma) tem de ser selecionado do
conjunto de sub-features.
• 1..* Pelo menos uma feature tem de ser seleccionada do conjunto de sub-features.
Figura 1.4. e-Shop [22]
A Figura 1.4 mostra uma possível representação para o modelo de features do
Sistema e-Shop [22].
18
Neste modelo são features obrigatórias Catalog, Payment, GUI e Info, são features opcionais Security, Banners, Offers, Search. A feature Security possui um grupo
de subfeatures numa alternativa XOR que indica que apenas uma delas é escolhida para
a aplicação. No caso da feature Payment, esta é composta por duas sub-features numa
alternativa OR (uma ou as duas podem ser escolhidas).
Note que uma feature filha pode aparecer apenas em um produto se sua feature
superior aparecer. A feature raiz é parte de todos os produtos dentro da LPS. Adicionalmente aos relacionamentos parental entre features, pode ocorrer também o que chamamos
de cross-tree entre features, que significa que uma feature pode estar relacionada a outra
só que não em uma relação de parentesco, podendo ser dos seguintes dois tipos:
• Requires. Se uma feature A requer a feature B, a inclusão de A em um produto
implica na inclusão também de B. No sistema de exemplo pagamento com cartão
de crédito deve implementar uma política de segurança alta.
• Excludes. Se a feature A exclui a feature B, ambas as features não podem fazer
parte do mesmo produto. No sistema de exemplo o produto que implementar uma
interface GUI mobile não deve incluir suporte a banners.
1.3.4. Configuration Knowledge
O feature model, por si só, apenas representa a modelagem do domínio, mas não representa o modo como os produtos deste domínio serão gerados a partir dos artefatos da linha
de produtos. O mapeamento entre o feature model e os artefatos de implementação é o
que se chama de Configuration Knowledge [12].
Os artefatos de implementação podem estar modelados direto no modelo que representa o configuration knowledge ou em um modelo a parte, neste caso o configuration
knowledge associará os artefatos de um modelo com as features do feature model.
Quando não estão dentro do configuration knowledge, os artefatos de implementação encontram-se em um modelo que assume diferentes nomes, dependendo da ferramenta utilizada, tais como family model, component model, architecture model, etc.
O mapeamento existente no configuration knowledge é essencialmente um conjunto de regras que definem que artefatos de implementação (classes, arquivos de recursos, etc) entram em cada produto da linha. Tomando o E-Shop 1.4 como exemplo em
um ambiente de desenvolvimento orientado a objetos, uma classe chamada Catalog (que
trata dos produtos disponíveis na loja) estaria representada no configuration knowledge
como uma regra que diz se a feature Catalog estiver selecionada em um produto, a classe
entraria nesse produto também, essencialmente uma relação de implica (feature implica
em artefato de implementação).
Por trás do processo de geração de produtos de uma linha de produtos de software se encontra uma engine de resolução de expressões lógica, que verifica se todas as
restrições presentes no feature model foram respeitadas em cada instância, e, para cada
seleção de features, verifica que artefatos de implementação estarão habilitados na instância. Uma vez que todas as verificações tenham sido realizadas, a saída do processo de
19
geração de produtos vai ter como resultado, para cada produto, uma lista dos artefatos de
implementação habilitados no produto.
Dependendo da ferramenta utilizada, o usuário pode especificar diretamente na
ferramenta o que será feito com essa lista, como gerar um projeto individual na IDE
utilizada com uma cópia de cada artefato de implementação, ou invocar um sistema de
empacotamento dos produtos que geraria os executáveis finais, permitindo assim uma
maior customização do processo de geração.
1.4. ENGENHARIA DE LINHA DE PRODUTOS DE SOFTWARE
1.4.1. Atividades Essenciais em Linha de Produtos de Software
Linhas de Produto de Software combinam três atividades essenciais e altamente interativas que se misturam práticas de negócios e tecnologia. Em primeiro lugar, atividade de
Core Asset Development onde o objetivo não é criar o produto final imediatamente e sim
visa o desenvolvimento de ativos a serem reutilizados em outras atividades posteriores.
Em segundo lugar, vem a atividade denominada Product Development que parte dos ativos base já desenvolvidos anteriormente reusando-os. Finalmente Management Activity,
que inclui gestão técnica e organizacional [16]. A Figura 1.5 mostra esta tríade de atividades essenciais. Cada círculo giratório representa uma das atividades essenciais. Todos os
três são ligados entre si e em movimento perpétuo, mostrando que todos os três são essenciais e estão intimamente ligados, podendo ocorrer em qualquer ordem, e são altamente
iterativos [17].
Figura 1.5. Atividades Essenciais [17]
20
1.4.1.1. Desenvolvimento de Ativos Base
Core Asset Development é uma atividade na forma de ciclo de vida que resulta em ativos
base que em conjunto compõem a plataforma da linha de produto [16]. O objetivo desta
atividade é definir os aspectos comuns e a variabilidade da linha de produtos, e, portanto,
obter artefatos reutilizáveis para em seguida possuir uma capacidade de produção maior
[21]. A Figura 1.6 mostra o núcleo desta atividade juntamente com suas saídas e insumos
necessários.
Figura 1.6. Desenvolvimento de Ativos Base [17]
As setas rotatórias na Figura 1.6 sugerem que não há um momento certo de adicionar uma restrição ou novos padrões no desenvolvimento e estas entradas afetam diretamente as saídas no processo. Em alguns contextos os produtos existentes são a base para
os ativos base em outros estes podem ser desenvolvidos do zero para futuro reuso.
Ativos base incluem, mas não estão limitados à arquitetura e sua documentação,
especificações, componentes de software, ferramentas como geradores de componentes
ou aplicação, modelos de desempenho, cronogramas, orçamentos, planos de teste, casos
de teste, planos de trabalho e processo descrições [17].
Embora possa ser possível a criação de ativos base que podem ser utilizados em
todos os produtos sem quaisquer adaptações, em muitos casos, algumas adaptações são
necessárias para torná-los mais utilizáveis no contexto mais amplo de uma linha de produtos. Logo, mecanismos de variação dos principais ativos base utilizados ajudam a controlar as adaptações necessárias e suportar as diferenças entre os produtos de software
[5]. Essas adaptações devem ser planejadas antes do desenvolvimento e facilitada para a
equipe de desenvolvimento do produto sem colocar em risco as propriedades existentes
dos ativos base.
21
1.4.1.2. Desenvolvimento de Produtos
Na atividade de desenvolvimento de produto, os produtos são desenvolvidos a partir dos
ativos base, com base no plano de produção, para satisfazer as exigências da linha de
produtos de software. Os insumos essenciais da atividade de desenvolvimento de produto
são requisitos, escopo da linha de produtos, ativos base e o plano de produção [3].
De posse do plano de produção, que detalha como os ativos base serão utilizados
para construir um produto, o engenheiro de software pode montar as partes da linha de
produtos. A Figura 1.7 ilustra o produto atividade de desenvolvimento, juntamente com
suas saídas e fatores contextuais.
Figura 1.7. Desenvolvimento de Produtos [17]
Como na Figura 1.5, as setas de rotação na Figura 1.7 indicam iterações entre as
partes envovidas. Por exemplo, a existência e a disponibilidade de um determinado produto pode assim afetar os requisitos de produtos subseqüentes. Como outro exemplo de
construção, um produto que tem em comunalidades previamente não reconhecidas em relação a outro produto da linha vai criar a necessidade de para atualização dos ativos base e
fornecer uma base para explorar essa comunilidade em futuros produtos [17]. Além disso,
esta atividade tem a obrigação de dar feedback sobre quaisquer problemas ou deficiências
encontradas com os ativos base.
1.4.1.3. Atividade de Gestão
A atividade de Management desempenha um papel vital no sucesso da institucionalização
da linha dentro de uma organização porque fornece e coordena a sua infra-estrutura necessária. Esta tarefa envolve atividades essenciais realizadas a nível técnico e organizacionais
para apoiar o ciclo de vida do processo [3].
A gestão supervisiona a construção dos ativos base e atividades de desenvolvimento do produto, garantindo que os grupos que constroem os ativos base e os grupos que
22
constroem os produtos estão plenamente envolvidos nas atividades individuais, acompanhando o processo definido para a linha de produtos acompanhando seu progresso [17].
Isto representa não apenas os aspectos técnicos mas também aspectos gerenciais e organizacionais.
O conjunto de ativos base e plano de como eles são usados para construir os produtos não nascem sem previamente estudar o ambiente, caracterizar o negócio, portanto
deve existir investimento organizacional. A gestão deve dirigir, controlar e garantir a plena
utilização dos ativos. Linhas de produtos de software está mais relacionado a práticas de
negócios do que práticas técnicas [17].
Embora as organizações sejam diferentes em termos da natureza de seus produtos,
de mercado ou missão, objetivos de negócio, estrutura organizacional, cultura e políticas,
as disciplinas de processo de software, e assim por diante, atividades essenciais aqui discutidas aplicam-se em qualquer situação, uma vez que representam o nível mais alto de
generalidade, que envolve os aspectos mais importantes sobre o desenvolvimento em LPS.
Em geral, as organizações realizam essa divisão de responsabilidades em uma
variedade de maneiras. Algumas organizações têm equipes dedicadas a cada função e
outros usam as mesmas pessoas para ambas. Depende da disponibilidade orçamentária,
estratégia entre outros aspectos. Na verdade, é válido mencionar que não há atividade
primária, isto é, em alguns contextos, os produtos já existentes são quebrados em ativos
base, enquanto que em outros, os ativos base podem ser desenvolvidos para uso futuro
[18].
De acordo com Clements e Northrop [17], em muitos casos, a parte da gestão é a
atividade responsável pelo sucesso ou fracasso do produto final de uma linha de produtos.
1.4.2. Abordagens de Construção de Linha de Produtos de Software
Segundo Chen [10], existem três abordagens principais de desenvolvimento em linha de
produtos de software (ver Figura 1.8):
• Proativa: Com esta abordagem os ativos base são desenvolvidos primeiro para
futuro produtos. Aqui são considerados todos os produtos a serem gerados previamente fazendo-se um planejamento inicial completo.
• Reativa: Nesta abordagem os ativos base já existem, bem como uma versão da linha
de produtos, o que acontece é a evolução desta linha realizando-se incrementos na
mesma à medida que novos requisitos aparecem.
• Extrativa: Com esta abordagem, inicialmente são analizados quais os produtos
já existentes e como eles são estruturados de modo a extrair as comunalidades e
variabilidades destes para então poder se derivar uma versão inicial da Linha de
Produtos.
Dependendo do grau de planejamento, a abordagem proativa pode ser classificada
em abordagem big bang e abordagem incrementa (ver Figura 1.9).
23
Figura 1.8. Abordagens em LPS
Na estratégia big bang, LPS é adotada para os novos produtos de uma só vez,
uma mudança drástica. Primeiramente a engenharia de domínio é construída completamente e a plataforma é modelada e desenvolvida. Quando os ativos base estão prontos a
engenharia de aplicação inicia e as aplicações são derivadas da plataforma [21].
Com abordagem incremental, os ativos base são gradualmente desenvolvidas para
suporte aos futuros produtos.
Já a abordagem reativa pode ser quebrada em três subcategories (ver Figura 1.9):
Figura 1.9. Subcategorias de abordagens em LPS [10]
• baseado em infra-estrutura,
24
• baseado em branch-and-unit, e
• baseado em bulk-integration.
A abordagem baseada em infra-estrutura não permite que os produtos individuais
estejam desatualizados em relação aos ativos base comuns a vários produtos, ou seja, a
plataforma deve manter sempre a integridade em relação aos produtos, exigindo que novas
características comuns sejam implementadas primeiro nos ativos base que irão compor os
produtos, em seguida, construindo os produtos.
Tanto o branch-and-unit quanto a abordagem bulk-integration permitem um desalinhamento temporário entre ativos base e os produtos individuais. A diferença entre estas
duas sub-abordagens está na quantidade de produtos que se espera ser lançado antes de
atualizar os ativos base.
A estratégia branch-and-unit exige que novas features comuns sejam reintegradas
nos ativos base imediatamente após o lançamento do novo produto, enquanto que bulkintegration permite que novas features comuns serem reintegrados após o lançamento de
um grupo de produtos.
Estas abordagens não são mutuamente exclusivas. Por exemplo, uma linha de
produtos pode ser adotada por meio de um abordagem proativa e, em seguida, evoluir
através de uma abordagem reativa.
1.4.3. Ferramentas
Nesta seção iremos abordar algumas ferramentas relacionadas basicamente à modelagem
de feature models.
Aguiar [2] realizou um estudo comparativo sobre as principais ferramentas de
apoio a Linha de Produtos de Software e abaixo seguem algumas características descritivas deste trabalho.
1.4.3.1. fmp
O fmp (Feature Model Plugin) é um plugin gratuito para o Eclipse desenvolvido pelo
Generative Software Development Lab, da University of Waterloo [1]. Ele utiliza como
base o Eclipse Modeling Framework, o que, de acordo com os desenvolvedores, reduziu
significativamente o esforço de desenvolvimento.
O fmp apenas apresenta suporte à modelagem do domínio, através de feature models. Ele não possui nenhuma funcionalidade de configuration knowledge, nem nada que
permita, dentro do próprio fmp, o mapeamento necessário entre features e artefatos da
linha de produtos para permitir a geração dos produtos.
Os modelos gerados pelo feature model são gravados no sistema como um arquivo
XML (do inglês Extensible Markup Language), o que pode permitir que geradores, utilizando XSLT (do inglês Extensible Stylesheet Language Transformation), por exemplo,
possam processar o modelo. Por ser um plugin para o Eclipse e possuir uma API bem
definida, possibilita que outras ferramentas se integrem com o mesmo.
25
Figura 1.10. Interface do fmp
O fmp implementa modelagem de features baseada em cardinalidades [13], ou
seja, permite a definição de cardinalidades de feature e de grupo, atributos de feature,
referências e anotações definidas pelo usuário.
Cardinalidades de feature e grupo permitem que sejam especificados o número
mínimo e máximo de filhos de uma feature que podem ser selecionados, 0 ou mais, 1 a 4,
por exemplo. Atributos de feature permitem que cada feature possua um valor, que pode
ser uma string, um booleano, um inteiro, etc, o que aumenta a expressividade do modelo.
Anotações definidas pelo usuário permitem que o usuário adicione novas propriedades
as features, além das básicas (nome, cardinalidade, valor), permitindo assim uma maior
customização do modelo.
Para suportar anotações definidas pelo usuário, o fmp permite que o usuário altere o meta-modelo do feature model, permitindo, por exemplo, que toda feature tenha
um atributo chamado "quantidade"; ou qualquer coisa que o usuário deseje colocar (Ver
Figura 1.10).
1.4.3.2. XFeature
O XFeature é um plugin para o Eclipse desenvolvido pela P&P Software, que é uma
empresa que se originou no Institute of Automatic Control of ETH (Swiss Federal Institute
of Technology).
26
O XFeature foi criado para demonstrar um conceito de uma ferramenta para automatizar o processo de modelagem e configuração de artefatos reusáveis de software.
A ferramenta se apresenta como inovadora pela possibilidade de customização do metamodelo da família de produtos [9].
O XFeature tem suporte à modelagem do domínio, através de feature models e não
possui a funcionalidade de configuration knowledge, que permite o mapeamento necessário entre features e artefatos da linha de produtos para permitir a geração dos produtos.
Originalmente o XFeature foi desenvolvido visando o seu uso em aplicações espaciais (sistemas de controle embutidos para naves espaciais, por exemplo), porém, não há
nenhuma restrição na maneira que foi desenvolvido que não permita o seu uso em outros
contextos.
Em relação à implementação, o XFeature foi implementado baseado na versão 3.3
do Eclipse, ao contrário do fmp, ele não utilizou o EMF para a definição do meta-modelo
de feature model. O seu editor é baseado no GEF (Graphical Editing Framework) do
Eclipse.
O XFeature depende fortemente de XML e de transformações XSL. Scripts Ant
são utilizados para a verificação e geração de arquivos de configuração da aplicação, tais
como os que customizam o editor dos modelos.
O processo de criação de modelos no XFeature é consideravelmente mais complicado do que nas outras ferramentas. Primeiramente se define qual será a configuração
utilizada (FD, FMP, SimplifiedICSR ou ICSR). Em seguida, é criado o que o XFeature
chama de family model, que é o meta-modelo do domínio. Após a validação do family
model sob a configuração utilizada, o usuário deve clicar em um botão que gera dois
meta-modelos: o de aplicação e o de display. O meta-modelo de aplicação é o que será
utilizado como configuração dos modelos que vão conter as instâncias da linha de produto, e o meta-modelo de display define quais os elementos visuais que aparecerão no
editor. Apesar de ser mais complicado, o XFeature permite que o usuário tenha mais controle sobre como são criados os feature models, uma vez que o usuário não fica preso à
única configuração presente nas outras aplicações.
Uma vez criados os modelos das instâncias da linha de produtos, eles podem ser
validados contra seu meta-modelo, que foi definido pelo usuário anteriormente. Quando
os modelos estiverem validados, eles podem ser utilizados como entrada pra outras ferramentas que possuam a parte de configuration knowledge para gerar os produtos finais.
A Figura 1.11 demonstra a interface do XFeature.
O XFeature só possui uma maneira de visualizar e editar os seus modelos, que é
em forma de árvore, como demonstrado na Figura 3, onde encontramos feature raiz, no
topo da árvore, features opcionais, pontilhadas, e features obrigatórias, em caixas amarelas, assim como o editor de propriedades de features. O XFeature também permite a
definição de restrições globais sobre o feature model. O usuário cria um modelo de restrições, que passa pelo global constraints compiler, que vai gerar um conjunto de arquivos
XSL que permitem a verificação das restrições.
27
Figura 1.11. Interface do Xfeature
1.4.3.3. pure::variants
O pure::variants é um plugin para o Eclipse desenvolvido pela pure-systems GmbH,
uma empresa que se originou no Institute Otto-von-Guericke-Universität Magdeburg e
no Fraunhofer Instituts Rechnerarchitektur und Softwaretechnik. A empresa tem como
objetivo o desenvolvimento de softwares para sistemas embarcados, que se baseia no
desenvolvimento de componentes de software e de ferramentas de desenvolvimento de
software.
O pure::variants foi desenvolvido para suportar o desenvolvimento e a implantação de linhas de produtos e famílias de software. O pure::variants provê suporte no
desenvolvimento durante as atividades de análise, modelagem, implementação e implantação.
O pure::variants apresenta suporte à modelagem do domínio, através de feature
models e possui a funcionalidade de configuration knowledge, que permite o mapeamento
necessário entre features e artefatos da linha de produtos para permitir a geração dos
produtos.
O pure::variants é uma ferramenta comercial, logo, requer licença para uso. Ela
possui uma versão gratuita para testes, que não pode ser usada comercialmente e possui
restrições no tamanho dos modelos. É sabido que o custo do pure::variants varia muito
dependendo da quantidade de licenças adquiridas. Mas sabe-se que normalmente o preço
de uma licença para uma máquina na versão developer custa em torno de 200 euros por
mês.
O custo também varia dependendo de qual versão da ferramenta será utilizada, a
Professional ou a Enterprise. A versão Enterprise possui controle de versões integrado
(utilizando CVS, por exemplo), permite que o usuário desfaça modificações no modelo
mesmo após ele ter sido fechado (não apenas quando ele está aberto, como ocorre na
28
Professional), colaboração on-line e gerenciamento de modelos centralizado.
O pure::variants utiliza uma notação baseada em FODA. Ele possui 3(três) tipos
de modelos diferentes: o feature model: onde são definidas as características comuns e
variabilidades da linha de produtos, o family model: a parte do configuration knowledge
onde se encontram os componentes que compõem os artefatos da linha de produtos, e o
variant model: que é o modelo que define uma instância da linha de produtos.
A divisão dos 3 modelos é clara e consideravelmente mais intuitiva do que os
inúmeros meta-modelos e modelos que o XFeature define, e a definição das instâncias em
arquivos separados facilita a organização da linha. Além disso, as mudanças no feature
model são sincronizadas automaticamente com os variant models.
Uma vez criados os variant models, eles podem ser validados para determinar
se cumprem as restrições do feature model, que foi definido pelo usuário anteriormente.
Uma vez que estes modelos estejam validados, eles podem ser usados juntamente com
o family model e o feature model para a geração dos produtos da linha, utilizando os
recursos de geração do pure::variants.
A Figura 1.12 apresenta o Family Model, onde encontramos componentes (as
caixas marrons), restrições (as expressões após a placa com exclamação), classes (as bolas
verdes com um "C"), aspectos (as bolas laranjas com um "A"), arquivos (o papel dobrado
na borda).
Figura 1.12. Interface de Edição do Family Model do pure::variants
29
1.5. Conclusões
Ao longo deste capítulo foram analizados diversos conceitos sobre LPS, propiciando ao
leitor uma visão geral sobre o assunto. Além disto foram mostradas características sobre
a notação F.O.D.A para construção de feature models bem como o que vem a ser uma
Configuration Knowledge, dentre outros conceitos e princípios.
Foi visto que as organizações podem obter benefícios de negócio consideráveis
em termos de redução de custos, redução do tempo de colocação no mercado, aumento
na qualidade do produto, etc, aplicando desenvolvimento de linhas de produto. Há, porém, riscos e custos associados à adopção das empresas para esta adoção que devem ser
avaliados antes de embarcar em uma iniciativa de reutilização deste tipo.
Organizações têm colocado projetos ad hoc em "stand by"a fim de deixar livre
recursos para construir ativos base de uma LPS. Isto implica em grandes custos, no etando
existem muitas experiências bem sucedidas deste tipo de empreendimento.
Portanto qualquer organização que desenvolve produtos como sistemas simples,
que tem bons conhecimentos do domínio do negócio e um nível razoavelmente elevado de
maturidade do processo, deve, pelo menos, fazer um estudo de viabilidade para observar
se o desenvolvimento de uma LPS pode ser benéfica para eles.
Referências
[1] GENERATIVE
SOFTWARE
DEVELOPMENT
GROUP.
http://www.sei.cmu.edu/plp/ web-page acessada em 14 de outubro de 2011.
[2] Rogerio Aguiar. Comparacao entre ferramentas para Linha de Produtos de Software. Escola Politecnica de Pernambuco. Departamento de Sistemas e Computacao.
http://dsc.upe.br/ tcc/20081/RogeriomonografiaFinal.pdf Acessado em 14 de outubro de 2011.
[3] F. Ahmed, P. Campbell, and M.S. Lagharid. Cognitive factors in software product
line engineering. In Computer Modelling and Simulation, 2009. UKSIM ’09. 11th
International Conference on, pages 352 –355, march 2009.
[4] Muhammad Ali Babar, Lianping Chen, and Forrest Shull. Managing variability in
software product lines. IEEE Software, 27:89–91, 94, 2010.
[5] Felix Bachmann and Paul C Clements. Variability in software product lines. Software Engineering Institute Pittsburgh USA, (September):46, 2005.
[6] Len Bass, Paul Clements, and Rick Kazman. Software Architecture in Practice.
Addison-Wesley Longman Publishing Co., Inc., Boston, MA, USA, 2 edition, 2003.
[7] Jan Bosch. Design and use of software architectures: adopting and evolving a
product-line approach. ACM Press/Addison-Wesley Publishing Co., New York,
NY, USA, 2000.
[8] Stan Buhne, Gary Chastek, Timo Kakola, Peter Knauber, Linda Northrop, and Steffen Thiel. S.: Exploring the context of product line adoption. In In: Proc. 5th Int.
Workshop on Product Family Engineering, 2003.
30
[9] V Cechticky, A Pasetti, O Rohlik, and W Schaufelberger. Xml-based feature modelling. Software Reuse Methods Techniques and Tools, pages 101–114, 2004.
[10] Y Chen, G C Gannod, and J S Collofello. A software product line process simulator.
Software Process: Improvement and Practice, 11(4):385–409, 2006.
[11] Sholom Cohen. Product line state of the practice report. Technical report, Software
Engineering Institute, Carnegie Mellon University, 2002.
[12] Krzysztof Czarnecki and Ulrich W. Eisenecker. Generative programming: methods,
tools, and applications. ACM Press/Addison-Wesley Publishing Co., New York,
NY, USA, 2000.
[13] Eisenecker U. Czarnecki K., Helsen S. Staged configuration using feature models,
software product lines. International Conference SPLC, 2004.
[14] K Kang. Feature-oriented domain analysis feasibility study. Technical report, SEI
Technical Report, 1990.
[15] Paul C. Clements Len Baas and Rick Kazman. Software Architecture in Practice.
Second Edition. SEI Series in Software Engineering. Addison-Wesley, 2003.
[16] Schmid K. Linden, F. J. v. d. and E. Rommes. Software Product Lines in Action:The
Best Industrial Practice in Product Line Engineering. Springer-Verlag, 2007.
[17] C.A. Long. Software product lines: practices and patterns [book review]. Software,
IEEE, 19(4):131 –132, jul/aug 2002.
[18] John D. McGregor, Linda M. Northrop, Salah Jarrad, and Klaus Pohl. Guest editors’
introduction: Initiating software product lines. IEEE Softw., 19:24–27, July 2002.
[19] Northrop. Software product line adoption roadmap. SEI Technical Note, 2004.
[20] SEI PLP. Framework for Product Line Practice. http://www.sei.cmu.edu/plp/, 2003.
[21] Klaus Pohl, Günter Böckle, and Frank J. van der Linden. Software Product Line
Engineering: Foundations, Principles and Techniques. Springer-Verlag New York,
Inc., Secaucus, NJ, USA, 2005.
[22] S. Segura, R.M. Hierons, D. Benavides, and Ruiz-Corte. Automated test data generation on the analyses of feature models: A metamorphic testing approach. pages
35 –44, april 2010.
[23] Arie van Deursen and Paul Klint. Domain-specific language design requires feature
descriptions. Journal of Computing and Information Technology, 10, 2001.
31
Capítulo
2
Chapter
1
Planejamento de capacidade de sistemas através
de Cadeias de Markov
Rubens Matos, Julian Araújo, Francisco Vieira e Paulo Maciel
Resumo
Neste capítulo, pretende-se definir formalmente as cadeias de Markov e demonstrar como elas podem ser utilizadas no planejamento de capacidade de sistemas computacionais, auxiliando na garantia de métricas de desempenho e disponibilidade. Serão
mostradas ferramentas que facilitam a análise de uma grande variedade de sistemas,
dando destaque a avaliação de redes de computadores e alguns tipos de sistemas distribuídos. Serão apresentados exemplos de avaliação de desempenho com métricas que
normalmente merecem interesse em diversos ambientes: tempo de resposta, taxa de conclusão de tarefas (throughput) e nível de utilização de recursos. Esses indicadores estão
diretamente relacionados à percepção do desempenho do sistema e podem também indicar a necessidade de mudanças, como atualização de componentes ou ajustes na configuração.
2.1. Introdução
1.
Em muitas atividades industriais, comerciais e humanas, bem como em fenômenos naturais, está presente um alto grau de incerteza ou risco. Neste sentido, modelos matemáticos
probabilísticos têm sido utilizados para fazer previsões de valores para ajudar nas tomadas
de decisões. Dentre os modelos probabilísticos, um que se destaca é conhecido como processo de Markov1 que corresponde a um fenômeno constituído de estados finitos e discretos, e cuja probabilidade de transição entre tais estados, num intervalo de tempo também
discreto, depende apenas do estado corrente e do estado seguinte. Uma sequência de estados seguindo este processo dá-se o nome de cadeia de Markov [20, 2, 4, 16, 22, 25]. Os
modelos Markovianos têm sido usados intensivamente na modelagem de desempenho e
dependabilidade desde a década de 50 [9]. As áreas onde os modelos de Markov podem
ser aplicados se incluem a Administração, Economia, Meteorologia, Física, Química e as
Engenharias.
1 Andrei
Andrejevitch Markov (1856-1922) - matemático russo.
32
Markov obteve os primeiros resultados para estes processos em 1906. Uma generalização para espaços de estados infinitos contáveis foi feita por Kolmogorov2 em 1936.
Cadeias de Markov estão relacionadas ao movimento Browniano e à hipótese ergódica,
dois importantes tópicos da Física nos primeiros anos do século XX, mas a motivação de
Markov para o desenvolvimento da teoria parece ter sido estender a teoria dos grandes
números a eventos dependentes.
Além do desempenho, aspectos de confiabilidade merecem grande atenção para a
garantia da qualidade do serviço prestado por um sistema. As cadeias de Markov podem
ser utilizadas para capturar o comportamento do sistema e permitir a descrição e previsão
de métricas de confiabilidade, como o tempo médio para falha, assim como a disponibilidade e o downtime anuais. A análise conjunta dos aspectos de desempenho e confiabilidade, chamada de análise de performabilidade, também será tratada neste estudo, uma
vez que muitos sistemas podem permanecer funcionais mesmo nas falhas. Além disso,
serão também apresentados os MRMs (Markov Reward Models) e uma introdução aos
modelos de
Neste capítulo, pretende-se mostrar como as cadeias de Markov podem ser utilizadas no planejamento de capacidade de sistemas computacionais, auxiliando na garantia de métricas de desempenho e disponibilidade almejadas. Serão apresentadas ferramentas que facilitam a análise de uma grande variedade de sistemas. Como exemplos, serão
utilizados estudos de avaliação de desempenho com métricas que normalmente merecem
interesse em diversos ambientes, como tempo de resposta, taxa de conclusão de tarefas (throughput) e nível de utilização de recursos. Esses indicadores estão diretamente
relacionados à percepção do desempenho do sistema e podem indicar a necessidade de
mudanças, tais como upgrade de componentes ou ajustes na configuração.
2.2. Fundamentação teórica
1.
Para entender o mecanismo das cadeias de Markov e suas aplicações, é essencial o conhecimento de conceitos fundamentais sobre probabilidade, diagramas de transição, vetor de probabilidade, matriz de transição, cadeia ergódica, cadeia regular e regime estacionário. Estes conceitos serão estudados a seguir.
2.2.1. Noções de probabilidade
1.
As noções de experimentação, espaço amostral e eventos são fundamentais para o estudo
da teoria da probabilidade. Para este estudo a noção de conjunto é fundamental. Os
conjuntos podem ser finitos ou infinitos. Os conjuntos infinitos podem ser enumeráveis
ou não-enumeráveis. Um conjunto infinito é enumerável se for possível construir uma
bijeção entre ele e o conjunto N dos números naturais.
Um experimento probabilístico é alguma ocorrência similar ao lançamento de uma
moeda ou de um dado, cujos resultados não são determinísticos. No caso do lançamento
de uma moeda, pode aparecer cara (H) ou coroa (T). No caso do lançamento de um dado
podem aparecer qualquer valor entre 1 e 6.
Espaço amostral. Define-se como espaço amostral, associado a um experimento, e
2 Andrey
Nilolaevich Kolmogorov (1903 - 1987) - matemático russo.
33
denota-se por S o conjunto de todos os possíveis resultados deste experimento, podendo
ser finito, infinito enumerável ou infinito não enumerável. Qualquer subconjunto do espaço amostral é conhecido como “evento”.
No caso do lançamento de uma moeda, S = {H, T }. No caso do lançamento de
um dado, S = {1, 2, 3, 4, 5, 6}. Se o experimento for o lançamento de 3 moedas ao mesmo
tempo, S = {HHH, T HH, HT H, HHT, T T H, T HT, T T H, T T T }, onde o elemento T T H
é diferente do elemento HT T devido à posição das caras e das coroas nos dois elementos.
Como um exemplo mais interessante para usuários da computação, pode-se citar
o espaço amostral derivado de um experimento que consiste na observação do número de
e-mails chegados ao provedor do NPD (Núcleo de Processamento de Dados) da UFPI em
cada dia. Este espaço amostral é infinito enumerável porque pode-se rotular cada e-mail
que chega com um único número natural, n ∈ N, ou seja, S = {n | n ∈ N}.
Outro exemplo interessante consiste na medida dos tempos de espera em um ponto
de ônibus. Neste caso, S é infinito e cada resultado é um número real não negativo, ou
seja, S = {t | t ≥ 0}.
A definição de eventos como um subconjuntos de um espaço amostral S, permite que as operações e propriedades típicas sobre conjuntos também possam ser a eles
aplicadas. Entre estas operações e propriedades se incluem a união, interseção e complementação, as leis da comutatividade, da associatividade, da distribuição, da identidade, da
idempotência, da dominação, da absorção e a lei de de Morgan e estas propriedades podem ser verificadas graficamente através dos diagramas de Venn. Além disso, elas podem
ser extendidas para qualquer número de eventos [25].
Cálculo de probabilidades. A forma clássica de se calcular a probabilidade de um
evento A, que será denotada por P(A), com m elementos em um espaço amostral finito
S = {a1 , a2 , · · · an }, onde os n pontos amostrais ai (i = 1, 2, · · · , n) devem ter a mesma
probabilidade de ocorrer, ou seja, eles são equiprováveis, é dada pela relação entre a quantidade de casos favoráveis ao evento A e a quantidade de elementos do espaço amostral S,
apresentada como um número real ou em percentagem. Ou seja, P(A) = mn .
Exemplo. Ao se retirar aleatoriamente uma carta de um baralho com 52 cartas, todas elas
1
têm a mesma probabilidade de ser a carta escolhida. Neste caso, a probabilidade será 52
.
4
No entanto, a probabilidade de que esta carta seja uma dama é 52 , uma vez que existem 4
damas em um baralho.
Eventos exclusivos. Dois eventos A e B são ditos mutuamente exclusivos ou disjuntos
se a interseção entre eles for vazia, ou seja, se A ∩ B = 0.
/ Se os eventos A e B forem
mutuamente exclusivos, então não é possível que ambos ocorram no mesmo experimento.
Diz-se que os eventos de uma lista são mutuamente exclusivos se todas as interseções
entre eles resultarem no evento nulo.
Eventos independentes. Diz-se que dois eventos são estatisticamente independentes se a
ocorrência de um deles não afetar a ocorrência do outro. Desta forma, dois lançamentos
seguidos de um mesmo dado constituem dois eventos independentes porque o resultado
do primeiro lançamento não tem qualquer influência sobre o resultado do segundo, e viceversa.
34
Multiplicação de probabilidades. Sendo Ai eventos independentes, a probabilidade da
ocorrência conjunta é definida pela regra da multiplicação
P(A1 .A2 . · · · An ) = P(A1 ∩ A2 ∩ · · · ∩ An ) = P(A1 ).P(A2 ). · · · .P(An )
Exemplo. No lançamento de duas moedas, a probabilidade de se obter duas caras é
1
4 = 0, 25 ou 25%. Este mesmo resultado pode ser obtido utilizando o fato dos dois
lançamentos serem independentes fazendo a multiplicação das probabilidades, ou seja,
P{HH} = P(H).P(H) = 21 . 21 = 14 .
Probabilidade condicionada. Se a condição de independência não for satisfeita, é necessário usar uma fórmula mais geral, que envolve as probabilidades condicionadas. Neste
caso, sendo dados dois eventos A e B, a probabilidade de que o evento B ocorra, mas com
a informação adicional de que o evento A já ocorreu, é denotada por P(B | A), que se lê:
“probabilidade de B dado que A já ocorreu”.
Exemplo. Seja a retirada ao acaso de uma carta em um baralho de 52 cartas e sejam
os eventos A = A carta é de paus e B = A carta é um 10. A probabilidade da carta
1
. Porém, a probabilidade da carta ser um 10, mas
selecionada ser um 10 de paus é 52
já sabendo antecipadamente que o naipe é paus, reduz o espaço amostral que passa a
ter somente 13 elementos, em vez de 52. Isto significa que a probabilidade com esta
1
inflormação é 13
.
De um modo geral, dados dois eventos não independentes A e B, a probabilidade
condicionada de A dado que B já aconteceu é dada por
P(A | B) =
P(A.B) P(A ∩ B)
=
P(B)
P(B)
Axiomas da probabilidade. Seja S um espaço amostral de um experimento randômico.
Se o evento A consistir do único ponto da amostra, s, então P(A) = P(s). A função de
probabilidade P deve satisfazer aos seguintes axiomas devidos a Kolmogorov.
A1 : 0 ≤ P(A) ≤ 1, para qualquer evento A ⊆ S.
A2 : P(S) = 1.
A3 : P(A1 ∪ A2 ∪ A3 ∪ · · · ) = P(A1 ) + P(A2 ) + P(A3 ) + · · · desde que todos os eventos
Ai sejam mutuamente exclusivos.
Exercícios resolvidos.
1. Para qualquer evento A, P(A) = 1 − P(A).
Prova: Como A e A são eventos mutuamente exclusivos, então S = A ∪ A. Pelo
axioma A2, P(S) = 1 = P(A) + P(A), donde P(A) = 1 − P(A).
2. Sendo 0/ o evento impossível, então P(0)
/ = 0.
Prova: Sabe-se que S = 0.
/ Logo, P(S) = 1 − P(S) = 1 − 1 = 0, pelo axioma A2.
35
Variáveis aleatórias. Dado um experimento e um espaço amostral S a ele associado,
denomina-se variável aleatória à função X que associa a cada elemento s de S um número
real X(s). Como pode ser notado, a definição de uma variável aleatória é a mesma
definição de função, o que pode gerar alguma dúvida, notadamente aos iniciantes neste
estudo.
Seja X uma variável aleatória. Se os valores de X formarem um conjunto finito ou
infinito enumerável, então X é denominada variável aleatória discreta. Se, no entanto,
este conjunto for um intervalo ou uma coleção de intervalos, ela é denominada variável
aleatória contínua.
Função de probabilidade. Seja X uma variável aleatória discreta. Sejam x1 , x2 , x3 , · · · ,
seus possíveis valores. A cada resultado xi associamos um número real p(xi ) = P(X = xi ),
que é a probabilidade do ponto xi , de forma que:
1. p(xi ) ≥ 0, para todo xi e
2. ∑∞
i=1 p(xi ) = 1
Esta função é denominada função de probabilidade da variável aleatória X.
Lei da probabilidade total. Sendo A e B dois eventos, sabe-se que a interseção de A com
o espaço amostral S é igual a A e que a interseção de B com seu complemento BC é o
conjunto vazio, ou seja,
A = A ∩ S e B ∪ BC = S
substituindo a segunda equação na primeira e aplicando-se o Teorema de de Morgan,
encontra-se
A = A ∩ (B ∪ BC ) = (A ∩ B) ∪ (A ∩ BC )
No entanto, os eventos A ∩ B e A ∩ BC são mutuamente exclusivos e isto pode ser
verificado através dos diagramas de Venn para dois conjuntos A e B. Desta forma, pode-se
utilizar o axioma A3 das probabilidades para encontrar
P(A) = P(A ∩ B) + P(A ∩ BC )
Esta equação além de facilitar os cálculos de probabilidade em muitas situações
pode ainda ser utilizada para qualquer partição de eventos que sejam mutuamente exclusivos. Neste caso, sendo dados n eventos mutuamente exclusivos, Bi , i = 1, 2, · · · , n de
um espaço amostral S e um evento qualquer A, a equação generalizada é dada por
n
P(A) = ∑ P(A ∩ Bi ), n ≥ 1
i=1
que é conhecida como a lei da probabilidade total. Esta equação normalmente é apresentada sob a forma de probabilidades condicionais, ou seja,
n
n
P(A) = ∑ P(A ∩ Bi ) = ∑ P(A | Bi )P(Bi )
i=1
i=1
36
Distribuição das probabilidades. Uma distribuição de probabilidades é um modelo
matemático que relaciona o valor da variável aleatória com a probabilidade de ocorrência desse valor no espaço amostral ou na população. Estes pontos, na forma (xi , p(xi )) ∈
S ×R, podem ser plotados em um gráfico para se verificar a forma como eles se distribuem
ao londo do espaço amostral S. Esta distribuição pode ser discreta ou contínua.
Distribuição discreta de probabilidades. Quando o parâmetro que está sendo medido só
pode assumir certos valores, como por exemplo valores inteiros 0, 1, 2, . . . , a distribuição
de probabilidades é chamada discreta. Por exemplo, o lançamento de um dado só pode
apresentar os resultados 1, 2, 3, 4, 5 e 6. Portanto a distribuição de suas probabilidades é
discreta.
Exemplo. Seja encontrar a distribuição discreta das probabilidades da variável aleatória
discreta que consiste no lançamento de três moedas. Neste caso o espaço amostral S =
{HHH, HHT, HT H, T HH, HT T, T HT, T T H, T T T } e X = {0, 1, 2, 3} (o número de caras).
Ou seja,
X = 0 ⇒ {T T T }
X = 1 ⇒ {HT T, T HT, T T H}
X = 2 ⇒ {HHT, HT H, T HH}
X = 3 ⇒ {HHH}
Desta forma, pode-se construir uma tabela como
xi
p(xi )
0
1
2
3
1
8
3
8
3
8
1
8
e plotar os pontos (xi , p(xi )) em um gráfico para se ter a noção da forma como a distribuição se comporta. Isto pode ser visto na Figura 2.1.
p(x i)
3/8
1/8
0
1
2
3
xi
Figure 2.1. Gráfico de uma distribuição discreta de probabilidades.
1.
Distribuição contínua de probabilidades. Quando a variável que está sendo analisada
tem valores em intervalos reais, a distribuição das probabilidades destes valores é contínua. Uma função matemática cujos valores sejam as probabilidades em cada ponto do
intervalo real, é chamada de função densidade de probabilidade, normalmente denotada
por fdp. A área sob a curva que expressa a fdp é igual a 1 que é o valor total das probabilidades. Esta forma pode ser verificada no gráfico da Figura 2.2.
A definição da função que dá a distribuição de probabilidades é feita encontrandose a função que passe pelos pontos (xi , p(xi ). Esta tarefa nem sempre á fácil de ser realizada. Felizmente existem alguns modelos de distribuição de probabilidades que podem
37
p
01
p
0,8
p
00
0,15
0,2
11
1
0
0
1
0,7
p
10
p
p
21
20
p
02
0,3
0,5
0,1
0,05
p
12
2
[
0,8 0,15
P = 0,7 0,2
0,5 0,3
2
p
0,2
a)
b)
22
0,05
0,1
0,2
]
c)
Figure 2.3. Diagrama de transições.
1
Uma cadeia de Markov é dita homogênea se para todos os estados i e j
P{Xn+1 = j | Xn = i} = P{Xn+m+1 = j | Xn+1 = i}
para n = 0, 1, 2, · · · e m ≥ 0. A probabilidade de ir para o estado j no passo n + 1 e para o
estado k no passo n + 2, dado que a cadeia está no estado i no passo n é dada por
P{Xn+2 = k, Xn+1 = j | Xn = i}
= P{Xn+2 = k, Xn+1 = j, Xn = i}P{Xn+1 = j | Xn = i}
= P{Xn+2 = k, Xn+1 = j}P{Xn+1 = j | Xn = i}
= p jk (n + 1)pi j (n)
onde foram usadas inicialmente as propriedades da probabilidade condicional e depois a
propriedade da cadeia de Markov. Uma sequência de estados visitados por uma cadeia é
chamada de caminho da amostra. Assim, p jk (n + 1)pi j (n) é a probabilidade do caminho
da amostra i, j, k que inicia no estado i no passo de tempo n.
Exemplo (uma cadeia de Markov não homogênea). Seja a cadeia discreta de Markov
{Xn , n = 1, 2, · · · } com apenas os estados a e b. No passo n a probabilidade de que a
cadeia permaneça em seu estado atual é dada por paa (n) = pbb (n) = 1/n, enquanto a
probabilidade de que ela mude de estado é pab (n) = pba (n) = (n − 1)/n, conforme pode
ser visualizado na Figura 2.4.
(n-1)/n
1/n
a
1/n
b
(n-1)/n
Figure 2.4. Uma cadeia de Markov de dois estados.
1
A matriz de transições é dada por
1/n
(n − 1)/n
P(n) =
(n − 1)/n
1/n
e as primeiras quatro matrizes de transições são dadas por
1 0
1/2 1/2
1/3 2/3
1/4 3/4
P(1) =
, P(2) =
, P(3) =
, P(4) =
0 1
1/2 1/2
2/3 1/3
3/4 1/4
38
As cadeias de Markov são casos particulares de processos estocásticos Markovianos, em que o número de estados possíveis é finito ou infinito enumerável. Na realidade, elas são tipos mais simples de processos estocásticos que possuem propriedades
importantes quando o número de transições cresce.
As propriedades a seguir são válidas para as cadeias de Markov.
1. Pi j ≥ 0 para quaisquer estados i e j.
2. Pi j ≤ 1 para quaisquer estados i e j.
3. ∑∞j=0 Pi j = 1 para todo i = 0, 1, 2, · · ·
Matriz de transição. Para efeito deste estudo, as probabilidades de transições dos estados
Xn = i para os estados Xn+1 = j são conhecidas como probabilidades de transições de
passo único ou apenas probabilidades de transições das cadeias de Markov, ou seja,
pi j = P{Xn+1 = j | Xn = i}, ∀n
A matriz P formada pelos elementos pi j da linha i e da coluna j, para todos os i
e j, é chamada de matriz de probabilidades de transições ou apenas matriz de transições.
Assim temos





P(n) = 



p00 (n) p01 (n) p02 (n)
p10 (n) p11 (n) p12 (n)
p20 (n) p21 (n) p22 (n)
..
..
..
.
.
.
pi0 (n) pi1 (n) pi2 (n)
..
..
..
.
.
.
···
···
···
..
.
···
..
.

p0 j (n) · · ·
p1 j (n) · · · 

p2 j (n) · · · 
..
.. 

.
. 

pi j (n) · · · 
..
..
.
.
Uma maneira simples de visualizar uma cadeia de Markov é através de uma
máquina de estados finitos ou por meio de um grafo dirigido, onde cada aresta é rotulada com as probabilidades de transição de um estado para o outro, sendo estes estados
representados pelos nós, conectados pelas arestas. Vamos introduzir esta idéia através de
um exemplo.
Exemplo. Considere uma cadeia de Markov que descreve as mudanças climáticas diárias
de uma dada localidade. Vamos considerar apenas três tipos de padrão de tempo: chuvoso (0), nublado (1) e ensolarado (2), onde o tempo é observado diariamente. Em um
determinado dia chuvoso, a probabilidade de que vai chover no dia seguinte é estimada
em 0, 8 e a probabilidade de que será nublado é de 0, 15, enquanto a probabilidade de que
o dia seguinte seja ensolarado é apenas 0, 05. Se um dia está nublado, a probabilidade
de que o dia seguinte também seja nublado é 0, 2, de que seja chuvoso é 0, 7, e de que
seja ensolarado é 0, 1. Se um dia é ensolarado, a probabilidade de que o dia seguinte seja
também ensolarado é 0, 2, de que o dia seguinte seja nublado é 0, 3 e de que o dia seguinte
seja chuvoso é 0, 5. Graficamente, isto pode ser observado na Figura 2.3, onde também
está mostrada a matriz de transições.
39
p
01
p
0,8
p
00
0,15
0,2
11
1
0
0
1
0,7
p
10
p
p
21
20
p
02
0,3
0,5
0,1
0,05
p
12
2
[
0,8 0,15
P = 0,7 0,2
0,5 0,3
2
p
0,2
a)
b)
22
0,05
0,1
0,2
]
c)
Figure 2.3. Diagrama de transições.
1
Uma cadeia de Markov é dita homogênea se para todos os estados i e j
P{Xn+1 = j | Xn = i} = P{Xn+m+1 = j | Xn+1 = i}
para n = 0, 1, 2, · · · e m ≥ 0. A probabilidade de ir para o estado j no passo n + 1 e para o
estado k no passo n + 2, dado que a cadeia está no estado i no passo n é dada por
P{Xn+2 = k, Xn+1 = j | Xn = i}
= P{Xn+2 = k, Xn+1 = j, Xn = i}P{Xn+1 = j | Xn = i}
= P{Xn+2 = k, Xn+1 = j}P{Xn+1 = j | Xn = i}
= p jk (n + 1)pi j (n)
onde foram usadas inicialmente as propriedades da probabilidade condicional e depois a
propriedade da cadeia de Markov. Uma sequência de estados visitados por uma cadeia é
chamada de caminho da amostra. Assim, p jk (n + 1)pi j (n) é a probabilidade do caminho
da amostra i, j, k que inicia no estado i no passo de tempo n.
Exemplo (uma cadeia de Markov não homogênea). Seja a cadeia discreta de Markov
{Xn , n = 1, 2, · · · } com apenas os estados a e b. No passo n a probabilidade de que a
cadeia permaneça em seu estado atual é dada por paa (n) = pbb (n) = 1/n, enquanto a
probabilidade de que ela mude de estado é pab (n) = pba (n) = (n − 1)/n, conforme pode
ser visualizado na Figura 2.4.
(n-1)/n
1/n
a
1/n
b
(n-1)/n
Figure 2.4. Uma cadeia de Markov de dois estados.
1
A matriz de transições é dada por
1/n
(n − 1)/n
P(n) =
(n − 1)/n
1/n
e as primeiras quatro matrizes de transições são dadas por
1 0
1/2 1/2
1/3 2/3
1/4 3/4
P(1) =
, P(2) =
, P(3) =
, P(4) =
0 1
1/2 1/2
2/3 1/3
3/4 1/4
40
Como pode ser observado pelas matrizes de transições, as probabilidades de que a
cadeia mude de estado vai aumentando, enquanto as probabilidades de que ela permaneça
nos estados anteriores vai diminuindo a medida que o tempo passa. Pode-se observar o
comportamento markoviano, onde cada matriz depende apenas do estado anterior e não
de outros estados. A probabilidade de que seja tomado o caminho que inicia no estado a e
permaneça neste estado após as duas primeiras transições e depois move-se para o estado
b lá permanece após o terceiro e quarto passos é dada por
P{X5 = b, X4 = b, X3 = a, X2 = a | X1 = a}
= paa (1)paa (2)pab (3)pbb (4)
= 1 × 1/2 × 2/3 × 1/4 = 1/12
2.3.1. Tipos de cadeias de Markov
1.
Cadeias de Markov podem ser classificadas quanto à natureza do tempo de transição entre
os estados, ou seja, discreto (DTMC - Discrete-Time Markov Chain) ou contínuo (CTMC
- Continuous-Time Markov Chain). Nas cadeias de Markov de Tempo Discreto as transições podem ocorrer somente em intervalos de tempo conhecidos, isto é, passo-a-passo.
Este é o caso dos exemplos apresentados anteriormente. Sistemas que são bem representados por DTMCs incluem aqueles onde as transições ocorrem seguindo uma base diária,
como visto na Figura 2.3, e aqueles que seguem um relógio discreto como o escalonador
de tarefas num computador. Se as transições entre estados puderem ocorrer em instantes
de tempo arbitrários (contínuos) a cadeia de Markov é uma CTMC. A propriedade Markoviana de ausência de memória é mantida para ambos os tipos de cadeias [2]. No caso da
DTMC, as transições obedecem a uma distribuição geomérica, pois esta é a única distribuição de tempo discreto que apresenta tal propriedade. No caso da CTMC, o tempo
das transições segue uma distribuição exponencial.
A Figura 2.5 é um exemplo simples de cadeia de Markov de tempo contínuo.
Neste caso, a matriz de transição é chamada de matriz geradora infinitesimal pois, neste
caso, as transições ocorrem com uma taxa, em vez de uma probabilidade, devido à natureza contínua desse tipo de modelo. Considerando o modelo da Figura 2.5, a matriz
geradora Q é composta por elementos qii e qi j , onde i 6= j e ∑ qi j = −qii , ou seja, em uma
CTMC os elementos da diagonal têm seus valores definidos de forma que a soma de cada
linha da matriz seja igual a 0. Considerando um espaço de estados S = {0, 1, 2}, a matriz
Q será:

 

q00 q01 q02
−0, 001 0, 001
0
0
−2
2 
Q =  q10 q11 q12  = 
q20 q21 q22
0, 2
0
−0, 2
Para calcular o vetor de probabilidade de uma CTMC, usa-se a Equação 1 (no
caso de probabilidades transientes, dependentes do tempo) ou o sistema de Equações 2
(no caso de probabilidades estacionárias, quando o tempo tende a infinito).
π 0 (t) = π(t)Q,
given π(0).
41
(1)
Figure 2.5. Uma cadeia de Markov de tempo contínuo.
1
πQ = 0, ∑ πi = 1
(2)
i∈S
Explicações detalhadas sobre como chegar a essas equações podem ser encontradas em [2].
Cadeias de Markov também podem ser classificadas de acordo com a frequência
com que seus estados podem ser alcançados ao longo do tempo. Em uma cadeia irredutível, cada estado pode ser alcaçado a partir de qualquer outro estado, de forma que
todos os estados são recorrentes3 nesse tipo de modelo. Se, uma vez que o sistema deixa
um determinado estado, aquele estado não puder mais ser visitado, a cadeia de Markov é
dita acíclica. Se uma cadeia não for acíclica nem irredutível, é classificada como phasetype [18]. Ela irá, eventualmente, alcançar um estado absorvente4 , mas enquanto isso
não acontece, a cadeia passa por um ou mais estados transientes5 . A Figura 2.6 mostra
exemplos dos três tipos de cadeias.
Figure 2.6. Tipos de cadeias de Markov de acordo com a frequência de visitas
aos estados.
1
3 Um
4 Um
estado é chamado recorrente se o sistema é capaz de retornar a esse estado inúmeras vezes [18].
estado é chamado absorvente se uma vez que ele é alcançado, a cadeia não for capaz de sair desse
estado.
5 Um estado é chamado transiente se, durante um período de tempo finito, o sistema visitar esse estado
um número finito de vezes [18].
42
2.3.2. Modelos Markovianos com Recompensa
.1
Os modelos Markovianos com recompensa (Markov reward models - MRM) [21] são
usados geralmente para obter métricas compostas, provendo a análise integrada de desempenho e confiabilidade, por exemplo. Para construir um MRM, uma taxa constante de
recompensa ri é associada a cada estado i de uma cadeia de Markov. Também é possível
associar taxas de recompensa às transições da cadeia [24], e nesse caso elas são conhecidas como recompensas de impulso (impulse rewards). Em geral, a recompensa associada
a um estado denota o nível de desempenho6 obtido pelo sistema enquanto encontra-se
naquele estado [18]. Usando novamente o modelo da Figura 2.5, se as taxas de recompensas forem definidas como um vetor r = (r1 , r2 , r3 ) = (5, 0, −2), representando a receita
obtida em cada estado, a taxa de reward instantânea esperada para o tempo t é:
E[X(t)] = ∑ ri πi (t) = 5π0 (t) + 0π1 (t) + −2π2 (t).
(3)
i∈S
E[X(t)] pode ser considerado como a receita média obtida pela operação do sistema no tempo t. Outros tipos de recompensa podem ser usados, tais como poder computacional, status de disponibilidade do sistema, finalização de tarefas por unidade de
tempo. Independentemente da taxa de recompensa, ri que é adotada, a recompensa esperada em estado estacionário pode ser computada na forma da Equação 4.
E[X] = ∑ ri πi
(4)
i∈S
Devido à possibilidade de calcular métricas como ganho médio em estado estacionário e ganho total em um determinado intervalo de tempo, os modelos Markovianos
de recompensa têm sido vastamente adotados em estudos de performabilidade, que combinam aspectos de performance e dependabilidade como ferramentas unificadas [23].
2.3.3. Modelos de geração automática
.1
DTMCs e CTMCs permitem a análise de muitos tipos de sistemas, com acurácia e poder
de modelagem adequados. Outros formalismos de modelagem, tais como as redes de
filas [7], redes de Petri estocásticas (SPNs) [15, 10], e redes de Petri determinísticas e
estocásticas (DSPNs) [11], podem ser consideradas técnicas de especificação de alto nível
para geração de cadeias de Markov. Esses formalismos são úteis em muitas ocasiões,
devido à possibilidade de explosão do espaço de estados da cadeia de Markov, à medida
que aumenta o número de componentes e a complexidade das interações num sistema.
Uma cadeia de Markov de tempo contínuo (CTMC) pode ser associada a uma
rede de Petri temporizada e estocástica. Em redes de Petri (RdP) isso é garantido devido
a ausência de memória no atraso dos disparos das transições (distribuição exponencial)
[14]. Nesse sentido, uma rede de Petri estocástica [8] é isomórfica ao formalismo da
CTMC.
6A
palavra “desempenho” aqui é usada num sentido amplo, significando qualquer aspecto mensurável
do comportamento do sistema.
43
(a) Exemplo de uma rede de Petri.
M0 = (1,0,0,0)
t0
t1
M1 = (0,1,0,0) M2 = (0,0,1,0)
t3
t2
M3 = (0,0,0,1)
t4
M0
(b) Árvore de alcançabilidade.
0
t0
t1
t4
2
1
t3
t2
3
(c) Cadeia de Markov.
Figure 2.7. Exemplo da equivalência entre cadeia de Markov e rede de Petri.
1
Adicionalmente, para auxiliar na geração da cadeia de Markov equivalente à rede
de Petri estocástica, constrói-se a árvore de alcançabilidade. A árvore de cobertura ou
alcançabilidade baseia-se na geração de uma árvore que possibilite a representação de
todas as possíveis marcações de uma RdP. A Figura 2.7(a) representa um modelo em
RdP, sua representação através da árvore de alcançabilidade (Figura 2.7(b)) e a cadeia de
Markov equivalente (Figura 2.7(c)).
A partir da árvore de alcançabilidade, pode-se construir a cadeia de Markov equivalente ao modelo. O espaço de estados da cadeia de Markov correspondente à árvore de
alcançabilidade de uma rede de Petri estocástica, sendo esta equivalente às marcações
encontradas. Por conseguinte, na Figura 2.7(b), a árvore de alcançabilidade possui 4 marcações que são equivalentes aos estados da Cadeia de Markov.
44
2.4. Modelos clássicos para avaliação de desempenho e disponibilidade
.1
Quando busca-se avaliar aspectos de desempenho e disponibilidade de um sistema, podem
ser gerados diferentes modelos, a depender da habilidade e experiência de quem os cria,
ou do nível de generalização utilizado, entre outras questões. Esta seção visa apresentar
exemplos de modelos que servem como base para muitos estudos, dos mais simples aos
mais complexos, envolvendo os aspectos de desempenho e disponibilidade de um sistema.
2.4.1. Cadeias de nascimento-morte
.1
Uma cadeia de Markov homogênea, irredutível, de parâmetro contínuo é denominada
processo de nascimento e morte se as únicas mudanças permitidas, a partir de um determinado estado i do processo, são para seus vizinhos imediatos, ou seja, para os estados
i + 1 (nascimento) ou para o estado i − 1 (morte). Um nascimento se processa com a taxa
λi e uma morte com a taxa µi , ou seja, dependem apenas do estado i. Este processo pode
ser visto graficamente na Figura 2.8.
λ0
λ1
1
0
μ1
μ2
λ3
λ2
3
2
μ3
λ4
4
μ4
...........
μ5
Figure 2.8. Diagrama de um processo de nascimento e morte.
1
Este tipo de cadeia de Markov é muito utilizado para representar sistemas que funcionam com base na simples chegada de requisições, que serão atendidas por n servidores.
A chegada de uma nova requisição é um nascimento na cadeia e, portanto, acontece com
uma taxa λi , ocupando um servidor do sistema. Já o serviço oferecido pelo sistema é efetuado a uma taxa µi , configurando-se como uma morte na cadeia, que libera um servidor
para atender outras possíveis requisições.
Aspectos importantes do desempenho do sistema podem ser conhecidos através
da probabilidade de se estar em determinados estados da cadeia de nascimento e morte.
Um exemplo é a probabilidade do sistema encontrar-se ocioso, que corresponde a π0 . Se
essa probabilidade for calculada para estado estacionário do sistema, ainda pode-se obter
o tempo médio (em horas) de ociosidade do sistema ao longo do período de um ano. Para
isso, basta multiplicar π0 por 8760 horas, que é corresponde ao número de horas de 1
ano. De forma semelhante, se o sistema possui somente n servidores e chegarem novas
requisições com uma taxa λn , que não poderão ser atendidas devido a todos os servidores
estarem ocupados, a probabilidade de uma requisição ser rejeitada devido ao sistema estar
completamente ocupado é calculada como πn · λn .
Sistemas de fila também podem ser representados por cadeias de nascimento e
morte, com a finalidade de se obter métricas como ocupação média da fila e nível de
utilização do sistema. O custo energético médio do sistema também pode ser calculado,
ao associar recompensas (rewards) referentes à energia consumida em cada estado da
cadeia.
45
2.4.2. Modelos simples de falha e reparo
.1
Quando se deseja analisar aspectos relacionados a eventuais falhas e reparos de um sistema computacional, um modelo simples como o apresentado na Figura 2.9 pode servir
como base para as construções de outras cadeias mais complexas. Nesse modelo, há
apenas 3 estados possíveis para o sistema: Funcionando, Quebrado, ou Em Reparo.
Considerando-se, por exemplo, que o sistema esteja funcionando, uma falha ocorrerá
com uma taxa λ , que deve ser igual ao inverso do tempo médio para falha do sistema,
conhecido como MTTF (Mean Time To Failure). Se o MTTF do sistema for 1000 horas,
então o valor de λ será 1/1000, ou 0, 001.
Figure 2.9. Diagrama de um modelo simples de falha e reparo.
1
A ocorrência de uma falha coloca o sistema no estado Quebrado, à espera de
que a equipe de reparo seja acionada e possa efetivamente iniciar o conserto. A taxa δ
corresponderá ao inverso desse tempo gasto desde a falha até o início do reparo. Se esse
tempo for de 30 minutos, δ será igual a 2, pois deve-se considerar o inverso do tempo
em horas (1/0, 5). A partir do instante em que o sistema já se encontra em reparo, caso o
tempo médio desta atividade seja 2 horas, a taxa µ será igual a 0, 5.
Dentre as métricas mais importantes que se pode obter deste modelo, estão o percentual de disponibilidade (ou indisponibilidade) em estado estacionário (A) e o downtime
(tempo de indisponibilidade) anual (D). O percentual de disponibilidade é calculado simplesmente através da probabilidade do sistema estar no estado Funcionando, πFuncionando .
É importante citar que o percentual de indisponibilidade (U) pode ser calculado indiretamente pelo percentual de disponibilidade, como 1 − A, ou diretamente através da soma
das probabilidades dos estados Quebrado e Em Reparo. Já o downtime anual, em horas,
será igual ao percentual de indisponibilidade multiplicado por 8760, que é o tempo em
horas correspondente a um ano. Obtém-se então D = U · 8760.
Cadeias de Markov mais complexas podem ser geradas ao conhecer aspectos de
falhas isoladas em componentes específicos de um sistema, de forma que ele continua
a funcionar mesmo após a quebra de algumas partes. Em muitos casos, o tamanho da
cadeia de Markov cresce exponencialmente à medida que mais componentes do sistema
vão sendo representados, com suas respectivas falhas e reparos independentes. Diante
deste fato, é comum utilizar algumas simplificações que tornam o modelo mais fácil de
ser entendido e diminui o tempo exigido para sua solução.
46
2.5. Ferramenta de apoio à modelagem e soluções de cadeias de Markov
.1
Nos últimos anos, diversos trabalhos têm sido desenvolvidos para avaliação e modelagem
de cadeias de Markov. Nesse sentido, algumas ferramentas são acadêmicas e comerciais.
Podemos citar Sharpe [3], JMT [3], Isograph [6] e R [17].
• SHARPE (Symbolic Hierarchical Automated Reliability and Performance Evaluator) é uma ferramenta acadêmica para modelagem e avaliação de desempenho,
disponiblidade, confiabilidade e performabilidade. A ferramenta suporta a modelagem através de árvore de falha, diagrama de blocos de confiabilidade, cadeia de
Markov, rede de Petri estocástica generalizada, entre outros.
• JMT (Java Modelling Tools) é um framework para avaliação de desempenho, planejamento de capacidade e estudos de caracterização de carga. A ferramenta disponibiliza a modelagem de cadeia de Markov, redes de filas, entre outros.
• Isograph é uma ferramenta comercial para modelagem e avaliação de confiabilidade, predição de confiabilidade e manutenção. Além disso, a ferramenta oferece
análise através de diagrama de blocos de confiabilidade, análise dos efeitos dos modos de falha, análise por árvores de eventos e análise de árvore de eventos e análise
de Markov.
• R é um ambiente open source para análises estatísticas e gráficos. Adicionalmente,
a ferramenta suporta a modelagem de cadeia de Markov.
2.6. Estudos de casos
.1
Os estudos de caso expostos a seguir ilustram algumas possibilidades de utilização das
cadeias de Markov, auxiliando na avaliação de cenários e descrevendo o comportamento
de sistemas que estão sempre exigindo altos níveis de desempenho, confiabilidade e
disponibilidade.
2.6.1. Planejamento de redundância em redes de computadores
.1
Este estudo de caso é baseado em [12] e apresenta o planejamento de redundância em
uma rede de computadores, com base na análise da disponibilidade prevista para cada
arquitetura. Apenas roteadores e enlances entre os roteadores são considerados aqui.
Duas cadeias de Markov de tempo contínuo foram construídas para analisar as
arquiteturas de rede visadas. Na Figura 2.10, a cadeia de Markov representa o cenário
mais simples, sem redundância. Há somente um enlace, rotulado como L0, conectando
o roteador R0 ao roteador R1. Nesse modelo, a operação normal de um componente é
denotada por um rótulo U (up/ativo), e um componente quebrado é representado por um
rótulo D (down/inativo). Nessa cadeia de Markov, um estado é definido por uma sequência
de rótulos, representado o roteador R0, roteador R1 e enlace L0, respectivamente. λR0 ,
λR1 e λL0 são as respectivas taxas de falha de R0, R1 e L0. De modo similar, µL0 , µR0
e µR1 são as taxas de reparo de cada componente do sistema. Uma vez que qualquer
componente (R0, R1, ou L0) tenha falhado, o sistema completo está num estado de falha
e consequentemente nenhuma falha adicional pode ocorrer até que o componente seja
47
reparado. Para esse modelo, o sistema está ativo e funcionando somente no estado UUU.
Todos os outros estados estão acinzentados na Figura 2.10, representando os estados de
falha do sistema.
Figure 2.10. Cadeia de Markov para a disponibilidade de uma rede sem redundância
1
A Figura 2.11 mostra a cadeia de Markov para o sistema com redundância em
nivel de enlace. A notação é similar à do modelo anteior. A condição ideal para esse
sistema é denotada pelo estado UUUU, no qual todos os componentes estão ativos, em
condições normais.
A cadeia mostra que o sistema pode falhar devido à quebra de um dos roteadores,
ou falhas em ambos os enlaces. Uma hipótese assumida nesse modelo é que há uma
política de reparo, que prioriza o enlace L0 sobre o enlace L1, quando ambos falharem.
Figure 2.11. Cadeia de Markov para a disponibilidade de uma rede com re1
dundância no enlace
Os MTTFs dos componentes usados nas duas arquiteturas são: 131.000 horas para
os roteadores e 11.988 horas para os enlaces. O tempo médio para reparo (MTTR) é igual
a 12 horas, para todos os compoentes. Note que todos os λi nos modelos são iguais a
1/MT T Fi e todos os µi são iguais a 1/MT T Ri . As taxas são exibidas em vez dos tempos
devido à sua forma compacta, que facilita o entendimento dos modelos.
A análise do modelo sem redundância, em estado estacionário, provê um valor de
0,9980 para a disponibilidade desse sistema. Calculando a mesma métrica com o modelo
48
que possui redundância de enlace obtém-se 0,9995. Esse aumento na disponibilidade se
traduz em uma redução do downtime anual de 7,53 horas para 1,88 horas, configurando-se
num ganho importante para empresas e organizações que precisam manter sua infraestrutura de comunicação funcionando de forma ininterrupta, sob pena de degradação da imagem corporativa e grandes prejuízos financeiros por quebras de contrato e/ou perda de
possíveis clientes. Além de servir para comparar as métricas estimadas para diferentes
arquiteturas candidatas, as cadeias de Markov aqui poderiam ser usadas para verificar até
que ponto aumentos na confiabilidade de um determinado componente podem suprir os
requisitos do sistema sem a necessidade de comprar e instalar equipamentos para servir
de réplicas dos servidores e dados críticos presentes no sistema.
2.6.2. Avaliação de desempenho e confiabilidade de composições de web services
.1
Este estudo de caso aborda inicialmente a análise de um processo de agente de viagem.
Tal sistema é composto de múltiplos serviços Web, exigindo passos específicos para completar a reserva de uma viagem. A Figura 2.12 mostra um diagrama de atividades UML
(Unified Modeling Language) para este processo, adaptado de [19].
Inicialização
Consulta - Aérea 2
Consulta - Aérea 1
Reserva - Aérea
Reserva - Hotel
Resp. ao cliente
Figure 2.12. Processo de agente de viagem.
1
No início do processo, o sistema de reserva de viagem busca simultaneamente
por vagas em duas companhias aéreas. Quando elas respondem, uma é escolhida com
base em algum critéiro tal como preço ou calendário. Se uma das linhas aéreas falhar
em responder, a outra é selecionada, e no caso de ambas falharem, o sistema agente de
viagem desiste e aborta. Outros passos incluem a invocação efetiva para reserva do bilhete
da companhia aérea, a reserva do hotel e a notificação de sucesso para o cliente. Qualquer
um dos web services pode falhar em responder e, neste caso, o sistema tenta se recuperar
através de reinicializações, exceto pela busca em companhias aéreas concorrentes.
Uma CTMC para esse sistema é exibida na Figura 2.13. Esse modelo foi construído para calcular o desempenho e a confiabilidade da composição de Web services e
49
Figure 2. 13. CTMC para a composição de Web services.
1.
assim planejar possíveis mudanças no sistema.
A tradução das atividades do modelo UML para os estados da cadeia de Markov
é quase direta, com exceção de poucos estados que foram adicionados. RIni, RAresv,
RHt, e RRep representam os estados de reinicialização do Web service após uma falha.
Por exemplo, quando o serviço de Inicialização falha, o sistema vai para o estado RIni,
de onde há 2 próximos estados possíveis: a) Inicialização, se a falha que ocorreu for
coberta, ou seja, se pode ser resolvida com a reinicialização; e b) Falha, se a falha não foi
resolvida pela reinicialização, de forma que o sistema inteiro falha. Os outros estados de
reinicialização tem significados similares.
Os parâmetros mrspi , mrspa1 , mrspa2 , mrspai , mrspht and mrsprep correspondem
ao tempo de resposta médio dos seguintes web services, respectivamente: inicialização,
consulta à companhia área 1, consulta à companhia aérea 2, reserva da passagem áerea
(invocação), reserva do hotel e resposta ao cliente. Os outros parâmetros seguem uma
notação similar. Note que algumas taxas de transição são iguais ao inverso do tempo de
resposta médio do Web service (mrspx ), ponderado pela probabilidade de que a transição
ocorra, isto é, a confiabilidade do respectivo Web service (rx ).
1−rx
. As taxas
Se qualquer web service x falhar, a taxa da transição será igual a mrsp
x
de transição saindo dos estados de reinicialização são iguais ao inverso do tempo médio
de reinicialização (mrx ), ponderado pelo fator de cobertura das falhas para aquele Web
service (Cx ), no caso de uma reinicialização com sucesso. Se a reinicialização daquele
web service não obtiver sucesso, o sistema faz uma transição para o estado Falha, com
x
uma taxa 1−C
mrx .
50
Table 2.1. Valores dos parâmetros para o modelo do Agente de Viagem.
1
Componente
Inicialização (init)
Consulta - aérea 1 (a1)
Consulta - aérea 2 (a2)
Invocação - cia. aérea (ai)
Reserva hotel (ht)
Resp. ao cliente (rep)
Conf. (r)
1,0
0,9
0,9
0,9
0,9
1,0
T resp. (mrsp)
1s
2s
2s
1s
2s
1s
Cobertura (C)
1,0
1,0
0.0
-
T reinic. (mr)
0,15 s
0,15 s
0,15 s
0,15 s
Os valores usados como base para a análise da cadeia de Markov são mostrados
na Tabela 2.1.
Analisando o modelo da Figura 2.13, se obtém, entre outras métricas, a probabilidade do sistema encontrar-se no estado “Completo” no instante t (πCompleto (t)). O
valor de πCompleto (t) é equivalente à probabilidade do tempo de resposta do sistema ser
menor ou igual ao tempo t: P[Resp ≤ t]. Supondo que o projetista, ou desenvolvedor,
desse sistema esteja interessado num tempo de resposta de 8 segundos, calculamos então
πCompleto (8) = 0, 5173, ou seja, há 51,83% de probabilidade do sistema responder em 8
segundos ou menos. Calculando essa probabilidade para diferentes valores de tempo t,
obtém-se a curva apresentada na Figura 2.14. Através dela, percebe-se que há uma probabilidade próxima a 100% de que o tempo de resposta seja no máximo 25 segundos. Esse
tipo de análise pode ser utilizada como base para a definição de contratos de nível de
serviço (SLA - Service Level Agreement) entre o provedor da aplicação de Agente de Viagem e seus clientes, fornecendo estimativas concretas sobre o desempenho da aplicação
em questão, já levando em consideração aspectos de confiabilidade.
1
Probabilidade
0,8
0,6
0,4
0,2
0
0
5
10
15
20
25
30
Tempo de resposta (s)
Figure 2.14. Curva de probabilidade de conclusão de acordo com o tempo.
1
2.7. Considerações finais e perspectivas
.1
Este capítulo tratou sobre a teoria que envolve as cadeias de Markov assim como sua utilidade no planejamento de capacidade de sistemas computacionais. Os exemplos de modelos e análises aqui apresentados servem como uma introdução capaz de guiar a construção
51
e análise de outros modelos mais sofisticados, possibilitando a avaliação do desempenho
e dependabilidade de vários tipos de sistemas. Espera-se que o leitor possa aproveitar o
máximo do texto, e aplicá-lo em ambientes reais, na academia e na indústria, expandindo
o conhecimento e a utilização deste formalismo e suas ferramentas associadas.
References
[1] BARROS, Mônica; Processos Estocásticos; Papel Virtual Editora; Rio de Janeiro;
2004.
[2] BOLCH, G., GREINER, S., de MEER, H., and TRIVEDI, K. S.; Queuing Networks
and Markov Chains: modeling and performance evaluation with computer science
applications; John Wiley and Sons; 2 ed.; 2001.
[3] BERTOLI, Marco and CASALE, Giuliano and SERAZZI, Giuseppe; JMT: performance engineering tools for system modeling; SIGMETRICS Perform. Eval. Rev.
vol36; March, 2009.
[4] GUNTER, B.; GREINER, S.; de MEER, H. and TRIVEDI, K. S.; Queueing Networks and Markov Chains: Modeling and Performance Evaluation with Computer
Science Applications; 2nd edition; John Wiley & Sons, Inc.; 2006.
[5] HAVERKORT, B. and MEEUWISSEN, A.; Sensitivity and uncertainty analysis of
Markov-reward models. IEEE Transactions on Reliability, 44(1):147–154; 1995.
[6] Isograph; Reliability Workbench 11 http://www.isograph-software.com/. Último
acesso em 09 de Outubro de 2011.
[7] KLEINROCK, L. Queueing Systems, volume 1. Wiley, New York; 1975.
[8] MACIEL, P. R. M.. LINS, R. D. and CUNHA, P. R. F.; Introdução às Redes de Petri
e Aplicações; Sociedade Brasileira de Computação; Campinas, São Paulo. 1996.
[9] MACIEL, P. R. M.; TRIVEDI, K.; MATIAS JR R.; and KIM, D.; Performance
and Dependability in Service Computing: Concepts, Techniques and Research Directions; Dependability Modeling. IGI Global, Hershey, Pennsylvania; 2011.
[10] AJMONE MARSAN, M., CONTE, G., and BALBO, G.; A class of generalized
stochastic petri nets for the performance evaluation of multiprocessor systems. ACM
Trans. Comput. Syst., 2:93–122. 1984.
[11] MARSAN, M. A. and CHIOLA, G.; On petri nets with deterministic and exponentially distributed firing times. In Advances in Petri Nets 1987, covers the 7th
European Workshop on Applications and Theory of Petri Nets, pages 132–145, London, UK. Springer-Verlag. 1987.
[12] MATOS JÚNIOR, R. de S., GUIMARÃES, A. P., CAMBOIM, K. M. A., MACIEL, P. R. M., TRIVEDI, K .S.; Sensitivity Analysis of Availability of Redundancy in Computer Networks. In Proceedings of the Third International Conference
on Communication Theory, Reliability, and Quality of Service, CTRQ 2010, pages
115–121, Budapest. IARIA. 2011.
52
[13] MENASCÉ, D. A.; ALMEIDA, V. A.; and DOWDY, L. W.; Performance by Design:
Computer Capacity Planning by Example. Prentice Hall PTR.; 2004.
[14] MOLLOY, Michael Karl; On the integration of delay and throughput measures in
distributed processing models; Phd Thesis; University of California, Los Angeles,
1981.
[15] MOLLOY, M. K.; Performance analysis using stochastic petri nets. IEEE Trans.
Comput., 31:913–917. 1982.
[16] NORRIS, J. R.; Markov Chains; Cambridge Series in Statistical and Probabilistic
Mathematics; 2009.
[17] R Project Page The R Project for Statistical Computing; http://www.r-project.org/.
Último acesso em 10 de Outubro de 2011.
[18] SAHNER, R. A., TRIVEDI, K. S., and PULIAFITO, A. Performance and reliability analysis of computer systems: an example-based approach using the SHARPE
software package. Kluwer Academic Publishers, Norwell, MA, USA; 1996.
[19] SATO, N. and TRIVEDI, K. S.; Stochastic modeling of composite web services for
closed-form analysis of their performance and reliability bottlenecks. In ICSOC,
pages 107–118; 2007.
[20] SHAMBLIN, James E.; Pesquisa Operacional: uma abordagem básica; Editora
Atlas, São Paulo, 1979.
[21] SMITH, M. R., TRIVEDI, S. K., and NICOLA, F. V.; The analysis of computer
systems using markov reward processes. Technical report, Durham, NC, USA; 1987.
[22] STEWART, William J.; Probability, Markov chains, queues and simulation: the
mathematical basis of performance modeling. 2009.
[23] TRIVEDI, K. S., MUPPALA, J. K., WOOLET, S. P., and HAVERKORT, B. R.;
Composite performance and dependability analysis. Performance Evaluation, 14(23):197–215; 1992.
[24] TRIVEDI, K. S., MALHOTRA, M., and FRICKS, R. M. Markov reward approach
to performability and reliability analysis. In Proceedings of the Second International
Workshop on Modeling, Analysis, and Simulation On Computer and Telecommunication Systems, MASCOTS ’94, pages 7–11, Washington, DC, USA. IEEE Computer Society. 1994.
[25] TRIVEDI, K. S.; Probability and Statistics with Reliability, Queuing, and Computer
Science Applications. John Wiley and Sons, 2nd. edition; 2002.
[26] TRIVEDI, K. S. and SAHNER, R.; SHARPE at the age of twenty two; doi =
http://doi.acm.org/10.1145/1530873.1530884; SIGMETRICS Perform. Eval. Rev.;
vol 36; ACM; March, 2009.
53
Capítulo
3
1
Computação Autonômica aplicada a Segurança de
Redes
Ariel Soares Teles, Francisco José da Silva e Silva, Zair Abdelouahab
Abstract
The constant increase in the number of computers networks attacks attempts has pushed
researchers community to devise better security strategies. However, the rapid growth
both in quantity and complexity of components and services offered in today’s networks
has increased the difficulty of administering these, making approaches based only on human interventions impracticable. In order to circumvent this problem, a modern approach called Autonomic Computing (AC) has gained attention from researchers related to
network security management. AC has the essence of self-management and the implementation of its concepts for network security systems introduces the ability of self-assurance.
This chapter aims to introduce the concepts of AC and shows their applicability to the
context of security in computer networks.
Resumo
O constante aumento no número de tentativas de ataques às redes de computadores leva a
uma busca por melhores estratégias de segurança. Porém, o grande crescimento tanto na
quantidade como na complexidade de componentes e serviços oferecidos nas atuais redes
tem aumentado a dificuldade de administração destas, tornando cada vez mais inviável
abordagens baseadas apenas em intervenções humanas. Com o objetivo de contornar
esta problemática, uma moderna abordagem denominada Computação Autonômica (CA)
tem ganho destaque nas pesquisas relativas ao gerenciamento da segurança de redes. CA
tem como essência o autogerenciamento e a aplicação de seus conceitos à segurança de
redes introduz no sistema a capacidade de autosegurança. Este capítulo tem como objetivo introduzir os conceitos de CA e mostrar sua aplicabilidade ao contexto de segurança
em redes de computadores.
54
3.1. Introdução
1
Segurança em redes de computadores compreende a área responsável pela proteção dos
dados que a transitam contra alterações indevidas, acesso não autorizado e indisponibilidade. Desde o surgimento da Internet, a busca por melhores estratégias de segurança
tem aumentado consideravelmente, tendo em vista a grande quantidade de tentativas de
ataques que vem sendo realizados. Esses ataques, quando bem sucedidos, tem causado
prejuízos financeiros e de imagem para empresas, instituições e pessoas físicas.
Existem vários obstáculos a serem enfrentados para se alcançar redes realmente
seguras, dentre eles pode-se destacar a existência de dependência dos sistemas de segurança por gerenciamento com intervenção humana, sendo este um processo que aumenta
continuamente o nível de dificuldade. O fato dos ataques à sistemas computacionais estarem se tornando cada vez mais sofisticados e as várias deficiências encontradas nos atuais
sistemas de segurança também são outros exemplos de obstáculos, como serão vistos
neste capítulo.
Tudo isso eleva a complexidade do problema da gerência de segurança e por isso
é interessante a utilização de recursos oferecidos pela Computação Autonômica (CA).
Sistemas de CA são capazes de gerenciarem a si próprios e se adaptarem dinamicamente
às mudanças a fim de restabelecer seu equilíbrio de acordo com as políticas e os objetivos
de negócio. Para isso, dispõem de mecanismos efetivos que os permitem monitorar, controlar e regular a si próprios, bem como recuperarem-se de problemas sem a necessidade
de intervenções externas.
A arquitetura e as propriedades de CA para a implementação de sistemas propõe
uma abordagem com muitas vantagens para ser aplicada à segurança de redes. Além
de apresentar características intrísecas de autogerenciamento, um elemento autonômico
provê outras funcionalidades que podem ser utilizadas para resolver problemas particulares à segurança de redes, com o uso de técnicas de aprendizagem e cooperação entre as
aplicações.
Neste capítulo será discutido os conceitos de CA e mostrado sua aplicabilidade
ao contexto de segurança em redes de computadores. A aplicação dos conceitos de CA
à segurança de redes introduz no sistema a capacidade de autosegurança, através da qual
serviços e funções de gerenciamento da segurança são executados sem a necessidade de
um gerente humano, a partir da definição de objetivos e parâmetros iniciais fornecidos
por seus administradores.
O restante deste trabalho está organizado da seguinte forma. Todos os fundamentos de CA são descritos na Seção 2, mostrando suas propriedades, arquitetura e detalhes
do ciclo autonômico. A Seção 3 irá descrever alguns conceitos de segurança em redes e
mostrar os problemas enfrentados por elas neste quesito. A necessidade que a segurança
em redes de computadores tem por mecanismos autonômicos e exemplos de trabalhos já
realizados em segurança autonômica de redes serão detalhados na Seção 4. Para finalizar
o capítulo, na Seção 5 serão apresentadas as conclusões.
55
3.2. Computação Autonômica
1
O termo Computação Autonômica surgiu em 2001, com um manifesto publicado por Paul
Horn, pesquisador da IBM, que lançou um desafio sobre o problema da crescente complexidade de gerenciamento do software [17]. O termo autonômico vem da biologia e
está relacionado às reações fisiológicas involuntárias do sistema nervoso [25]. No corpo
humano, o sistema nervoso autonômico cuida de reflexos inconscientes, isto é, de funções corporais que não requerem nossa atenção como a contração e expansão da pupila,
funções digestivas do estômago e intestino, a frequência e profundidade da respiração, a
dilatação e constrição de vasos sanguíneos, etc. Esse sistema reage às mudanças, ou perturbações, causadas pelo ambiente através de uma série de modificações, a fim de conter
as perturbações causadas ao seu equilíbrio interno.
Em analogia ao comportamento humano, diz-se que um sistema computacional
está em equilíbrio quando o seu ambiente interno (formado pelos seus subsistemas e pelo
próprio sistema) está em proporção devida com o ambiente externo. Conforme observaram Parashar e Hariri em [27] e detalhado em [28], se o ambiente interno ou externo
perturba a estabilidade do sistema, ele sempre atuará de modo a recuperar o equilíbrio
original. Dessa forma, os sistemas de CA são sistemas capazes de se autogerenciarem
e se adaptarem dinamicamente às mudanças a fim restabelecer seu equilíbrio de acordo
com as políticas e os objetivos do negócio do sistema [17]. Para isso, devem dispor de mecanismos efetivos que os permita monitorar, controlar e regular a si próprios, bem como
recuperarem-se de problemas sem a necessidade de intervenções externas.
3.2.1. Propriedades de Sistemas Autonômicos
1
A essência da CA é o autogerenciamento. Para implementá-lo, o sistema deve ao mesmo
tempo estar atento a si próprio e ao seu ambiente. Desta forma, o sistema deve conhecer
com precisão a sua própria situação e ter consciência do ambiente operacional em que
atua. Do ponto de vista prático, conforme Hariri [13], o termo computação autonômica
tem sido utilizado para denotar sistemas que possuem as seguintes propriedades:
• Autoconsciência (self-awareness): O sistema conhece a si próprio: seus componentes e inter-relações, seu estado e comportamento;
• Consciência do contexto (context-aware): O sistema deve ser ciente do contexto
de seu ambiente de execução e ser capaz de reagir a mudanças em seu ambiente;
• Autoconfiguração (self-configuring): O sistema deve ajustar dinamicamente seus
recursos baseado em seu estado e no estado do ambiente de execução;
• Auto-otimização (self-optimizing): O sistema é capaz de detectar degradações de
desempenho e de realizar funções para auto-otimização;
• Autoproteção (self-protecting): O sistema é capaz de detectar e proteger seus recursos de atacantes internos e externos, mantendo sua segurança e integridade geral;
• Autocura (self-healing): O sistema deve possuir a habilidade de identificar potenciais problemas e de se reconfigurar de forma a continuar operando normalmente;
56
• Aberto (open): O sistema deve ser portável para diversas arquiteturas de hardware
e software e, consequentemente, deve ser construído a partir de protocolos e interfaces abertos e padronizados;
• Capacidade de Antecipação (anticipatory): O sistema deve ser capaz de antecipar, na medida do possível, suas necessidades e comportamentos considerando seu
contexto e de se autogerenciar de forma pró-ativa.
As propriedades de autoconfiguração, auto-otimização, autocura e autoproteção
são suficientes para realizar a visão original do termo [25]. Para a incorporação das propriedades de auto-otimização e autocura, mecanismos de autoconsciência, consciência de
contexto e autoconfiguração devem ser requisitos do sistema.
3.2.2. Arquitetura de um Sistema Autonômico
1
Arquiteturas de sistemas autonômicos visam formalizar um quadro de referência que
identifica as funções comuns e estabelece os alicerces necessários para alcançar a autonomia. Em geral, essas arquiteturas apresentam soluções para automatizar o ciclo de
gerenciamento de sistemas, conforme mostrado na Figura 3.1, o qual envolve as seguintes
atividades:
Figura 3.1. Ciclo de gerenciamento de sistemas [5].
1
• Monitoramento ou Medição: Coleta, agrega, correlaciona e filtra dados sobre
recursos gerenciados;
• Análise e Planejamento: Analisa os dados coletados e determina se devem ser
realizadas mudanças nas estratégias utilizadas pelo recurso gerenciado;
• Controle e Execução: Escalona e executa as mudanças identificadas como necessárias pela função de análise e decisão.
3.2.2.1. MAPE-K
1
Em 2003 a IBM propôs uma versão automatizada do ciclo de gerenciamento de sistemas
chamado de MAPE-K (Monitor, Analyse, Plan, Execute, Knowledge) [17], representado
57
na Figura 3.2. Este modelo está sendo cada vez mais utilizado para inter-relacionar os
componentes arquiteturais dos sistemas autonômicos. De acordo com essa arquitetura,
um sistema autonômico é formado por um conjunto de elementos autonômicos.
Um elemento autonômico contêm um único gerente autonômico que representa e
monitora um ou mais elementos gerenciados (componente de hardware ou de software)
[19]. Cada elemento autonômico atua como um gerente responsável por promover a produtividade dos recursos e a qualidade dos serviços providos pelo componente do sistema
no qual está instalado.
Figura 3.2. MAPE-K: Ciclo de gerenciamento autonômico [16].
1
No ciclo MAPE-K autonômico (Figura 3.2), o elemento gerenciado representa
qualquer recurso de software ou hardware o qual é dado o comportamento autonômico
através do acoplamento de um gerenciador autonômico, podendo ser por exemplo um
servidor Web ou banco de dados, um componente de software específico em um aplicativo
(por exemplo, o otimizador de consulta em um banco de dados), o sistema operacional,
um conjunto de máquinas em um ambiente de rede, etc.
Os sensores (sensors) são responsáveis por coletar informações do elemento gerenciado. Estes dados podem ser os mais diversos possíveis, por exemplo, o tempo de
resposta das requisições dos clientes, caso o elemento gerenciado seja um servidor Web.
As informações coletadas pelos sensores são enviadas aos monitores (monitors) onde são
interpretadas, preprocessadas e colocadas em um nível mais alto de abstração, para então
serem enviadas para a etapa seguinte no ciclo, a fase de análise e planejamento (analyze
and planing). Nesta fase, tem-se como produto uma espécie de plano de trabalho, que
consiste de um conjunto de ações a serem executadas pelo executor (execute). O componente responsável por fazer as alterações no ambiente é chamado de atuador (effectors).
Somente os sensores e atuadores possuem acesso direto ao elemento gerenciado. Durante
todo ciclo de gerenciamento autonômico, pode haver a necessidade de uma tomada de
decisão, dessa forma, faz-se necessário também a presença de uma base de conhecimento
(knowledge), sendo que esta é comumente mais explorada na fase de análise e planejamento [8].
Isso é implementado utilizando dois ou mais ciclos de gerenciamento autonômico,
um ou mais ciclos de controle local e um global. Os ciclos de controle local tratam apenas
58
de estados conhecidos do ambiente local, sendo baseado no conhecimento encontrado no
próprio elemento gerenciado. Por esta razão, o ciclo local é incapaz de controlar o comportamento global do sistema. O ciclo global, por sua vez, a partir de dados provenientes
dos gerenciadores locais ou através de um monitoramento a nível global, podem tomar decisões e atuar globalmente no sistema. No entanto, a implementação das interações entres
os diversos níveis existentes vai depender das necessidades e das limitações da aplicação.
3.2.3. Monitoramento
1
O monitoramento corresponde a primeira fase do ciclo autonômico MAPE-K. Nesta
etapa, sensores são utilizados com a finalidade de obter dados que reflitam mudanças
de comportamento do elemento gerenciado ou informações do ambiente de execução que
sejam relevantes ao processo de autogerenciamento. Os sensores são dispositivos de hardware ou software que estão diretamente ligados ao componente que se deseja monitorar.
O tipo de informação coletada bem como o modelo do(s) monitor(es) empregados
são específicos para cada tipo de aplicação. Contudo, alguns requisitos são comuns entre
eles, tais como a filtragem, a escalabilidade, a dinamicidade e a tolerância a falhas [23].
Um monitor deve prover filtragem, pois a quantidade de dados coletados pode crescer
muito rapidamente e consumir recursos de transmissão, processamento e armazenamento.
Grande parte desses dados podem ser de pouca relevância e, portanto, descartá-los não
implicaria em prejuízo. Considerando-se que um sistema pode crescer indefinidamente,
contendo inúmeros objetos sob monitoramento, a tarefa dos monitores não pode consumir
recursos e reduzir o desempenho do sistema. Em contrapartida, as mudanças no ambiente ou no comportamento do sistema não podem afetar o serviço de monitoramento [9].
Além disso, falhas podem ocorrer e o monitor pode apresentar algum comportamento atípico ou mesmo parar de funcionar completamente. Dessa forma, devem ser levadas em
consideração provisões como redundância e mecanismos de recuperação de falhas dos
monitores.
3.2.3.1. Classificação de Sistemas de Monitoramento
1
Aplicações autonômicas possuem requisitos de monitoramento diferentes, variando os
elementos que se deseja monitorar. De acordo com as características deste elementos
podem ser implementadas formas de monitoramento específicas. Em [16], Huebscher e
McCann identificaram dois tipos de monitoramento em sistemas autonômicos, classificados de acordo com o tipo de sensor utilizado:
• Monitoramento Passivo: No monitoramento passivo os dados obtidos de monitoramento são fornecidos pelo sistema sem necessidade de nenhuma alteração na
aplicação. Por exemplo, no Linux, informações sobre uso de CPU e memória podem ser coletados do diretório /proc;
• Monitoramento Ativo: No monitoramento ativo para que se possa fazer a captura
de dados é necessário alterar a implementação da aplicação ou sistema operacional.
São exemplo desse tipo de monitoramento, sensores que são inseridos na forma de
bytecodes em aplicações Java.
59
Conforme observado nos trabalhos de [23] e [16], foi possível constatar que o
monitor também pode ser classificado quanto à estratégia utilizada:
• Monitoramento orientado à eventos: Eventos são ações que acontecem no sistema e podem alterar o seu estado, por exemplo o “processo ocioso”, “processo
em execução”, “início do processo”, “chegada de uma requisição”, etc. Os eventos
acontecem instantaneamente e portanto nesse tipo de monitoramento cada evento
corresponde a um dado que é transmitido para o monitor. Essa abordagem pode ser
aplicada nos casos em que a taxa de ocorrência de eventos é muito baixa. A desvantagem é que o número de eventos gerados pode ser muito grande e informações
redundantes e desnecessárias estariam sobrecarregando os recursos do sistema;
• Monitoramento orientado ao tempo: Nessa estratégia, o monitor coleta os dados
de forma periódica, ou seja, um intervalo de tempo é definido para que o monitor
consulte as informações do ambiente em busca de eventos significativos. A grande
dificuldade encontrada nessa estratégia está em definir o melhor intervalo para a
realização da coleta. A desvantagem nesse caso seria que informações importantes
seriam perdidas durante esse intervalo;
• Monitoramento autonômico: As duas estratégias acima podem ser intercaladas
conforme ocorrem as mudanças no ambiente. Por exemplo, se a taxa de ocorrência
de eventos está elevada a melhor estratégia seria a orientada ao tempo. O tamanho
do intervalo de tempo na segunda estratégia também pode ser refinado segundo uma
abordagem autonômica de acordo com as características do ambiente.
3.2.4. Análise e Planejamento
1
A análise vem após o monitoramento no ciclo de gerenciamento MAPE-K, tendo como
fase seguinte o planejamento. Em geral estas duas fases são geralmente implementadas
em um único componente. O processo de análise e planejamento é essencial para autonomia do sistema, pois é nele que são geradas as decisões sobre quais modificações serão
realizadas no sistema, que corresponde ao elemento gerenciado.
A fase de análise e planejamento recebe como entrada os eventos e seus dados
gerados pelo sistema de monitoramento e gera como saída um conjunto de ações, também
chamado de plano de ações. Estas ações correspondem às operações de reconfiguração
que, de acordo com o mecanismo de tomada de decisão, devem ser executadas no sistema
a fim de manter o equilíbrio do sistema considerando seus objetivos. Muitas técnicas
podem ser empregadas na fase de análise e planejamento, entre as quais se destacam
o uso de funções de utilidade, aprendizado por reforço e regras Evento-Condição-Ação
(ECA). Sendo esta última detalhada a seguir.
3.2.4.1. Análise e Planejamento Baseados em Regras ECA
1
Regras do tipo evento-condição-ação (ECA Rules) determinam as ações a serem realizadas quando um evento ocorre desde que certas condições sejam satisfeitas. De acordo
com [5], ECA rules são especificações declarativas de regras ou regulamentações que
60
determinam o comportamento de componentes de aplicações. Para cada evento são definidos um conjunto de regras que podem gerar uma ou mais ações. Esses eventos também
podem satisfazer as condições de diferentes regras e algumas dessas regras podem gerar
ações que conflitam entre si. Nem sempre esses conflitos podem ser detectados durante a
escrita das regras, sendo muitas vezes descobertos em tempo de execução.
Em ECA rules o evento especifica quando as regras deverão ser acionadas. A
condição é a parte a ser verificada, podendo esta ser satisfeita ou não. E por fim, a ação,
a qual representa a operação a ser realizada caso a condição seja satisfeita. São definidas
da seguinte forma:
on event if condition do action;
Figura 3.3. Definição de uma regra do tipo ECA.
1
3.2.5. Execução de Ações de Reconfiguração
1
Na etapa de execução do ciclo MAPE-K são realizadas reconfigurações no sistema de
forma a restabelecer seu equilíbrio. A finalidade da reconfiguração é permitir que um sistema evolua (ou simplesmente mude) incrementalmente de uma configuração para outra
em tempo de execução, introduzindo pouco (ou, idealmente, nenhum) impacto sobre a
execução do sistema. Desta forma, os sistemas (ou aplicações) não necessitam ser finalizados, ou reiniciados, para que haja as mudanças.
A autoconfiguração (self-configuring) é a característica do sistema autônomo que
o permite ajustar-se automaticamente às novas circunstâncias percebidas em virtude do
seu próprio funcionamento, de forma a atender a objetivos especificados pelos processos
de autocura, auto-otimização ou autoproteção [5].
O processo de reconfiguração é realizado pelos executores através dos atuadores.
Executores recebem como entrada um plano de ações gerado na etapa de análise e planejamento e utiliza os atuadores pertinentes para implementar as ações de reconfiguração
descritas no plano. As reconfigurações devem ser realizadas dinamicamente, sem impor
a necessidade de parar e/ou reiniciar o sistema.
Segundo [24], duas abordagens gerais têm sido utilizadas para atingir adaptação:
adaptação paramétrica e adaptação composicional. A adaptação paramétrica consiste na
alteração de variáveis que determinam o comportamento do sistema. Já a adaptação composicional (ou estrutural) consiste na substituição de algoritmos ou partes estruturais de
um software, permitindo que este adote novas estratégias (algoritmos) para tratar situações que não foram inicialmente previstas na sua construção.
3.2.5.1. Questões de Projeto de Mecanismos de Reconfiguração
1
O desenvolvimento de um mecanismo de reconfiguração dinâmica não é algo simples.
Diversos requisitos devem ser considerados a fim de manter as características e funcionalidades do sistema [26], entre as quais destaca-se:
61
• Separação de responsabilidades: No desenvolvimento de sistemas autonômicos,
a separação de responsabilidades permite que o código funcional da aplicação (responsável pelas regras de negócio) seja separado do código responsável pela adaptação. Isto simplifica o desenvolvimento, a manutenção e o reuso do código adaptativo;
• Confiabilidade: Um problema quando se modifica um sistema em tempo de execução é a sincronização entre reconfigurações e execução funcional do sistema.
A reconfiguração não deve prejudicar a funcionalidade do sistema. Léger et al.,
em [22], definiram um conjunto de propriedades a fim de garantir a confiabilidade
no contexto das reconfigurações dinâmicas em sistemas baseados em componentes. Esse conjunto de propriedades foi baseado em transações e denominado ACID
(Atomicidade, Consistência, Isolamento e Durabilidade);
• Preservação de consistência: Quando a reconfiguração do sistema ocorre em tempo
de execução, é importante que a reconfiguração preserve a consistência do sistema.
O estado do sistema interno deve ser mantido e as informações trocadas entre os
componentes não devem ser perdidas;
• Custo da reconfiguração: Em [11] o custo de reconfiguração é definido como
uma medida dos efeitos negativos introduzidos pela reconfiguração. Esses efeitos
negativos incluem, por exemplo, a indisponibilidade temporária do serviço, ou a
perturbação induzida em outros serviços após o possível aumento do consumo de
recursos de rede durante a reconfiguração. A relação custo/benefício deve ser avaliada.
3.3. Segurança em Redes de Computadores
1
O grande crescimento na quantidade de componentes e serviços oferecidos nas atuais
redes de computadores tem aumentado o nível de complexidade no trabalho de gerenciamento e administração destas. Cada vez mais são integrados novos dispositivos às redes,
que requerem conectividade a qualquer momento e em qualquer lugar, além de se caracterizarem por sua heterogeidade que dificulta o processo de padronização das aplicações.
Então se faz necessário aplicar a ideia de CA às Redes de Computadores, através
da atribuição da capacidade para gerenciarem a si próprias, denominadas então como
Redes Autonômicas [3]. Os serviços e funções de gerenciamento da rede são executados
sem a necessidade de um gerente humano de maneira transparente para seus usuários,
havendo apenas a necessidade de objetivos e parâmetros iniciais, os quais o sistema leva
em consideração. A rede deve ser capaz de aprender com as ações dos seus componentes
através da análise dos resultados obtidos. A capacidade de adaptação e aprendizagem são
as características das redes autonômicas.
Neste cenário, não se pode deixar de lado a segurança da informação, que é requisito fundamental para o bom funcionamento de qualquer sistema computacional, compreendendo o conjunto de medidas que visam preservar e proteger as informações e os
sistemas de informação. Visto que essas redes estão conectadas quase sempre à Internet,
as aplicações residentes nelas podem sofrer com atividades maliciosas originadas a partir
de qualquer usuário conectado à rede.
62
É normal que o acesso à rede mundial de computadores ofereça a possibilidade de
descoberta e exploração de vulnerabilidades de forma bem rápida, quase sempre mais do
que a atualização das ferramentas de segurança e da emissão de correções pelos fabricantes de softwares. Então o número de incidentes de segurança cresce muito rapidamente
juntamente com a quantidade de danos causados. No entanto, proporcionalmente tem
crescido também as pesquisas de novos mecanismos e técnicas para aumentar o nível de
segurança. Políticas de acesso, uso de firewalls, sistemas de detecção de intrusão, sistemas
de prevenção de intrusão, honeypots, entre outros, tem sido essas contra medidas.
Em segurança da informação é possível identificar os seguintes propriedades básicas, consideradas também os pilares para a segurança de redes [20]:
• Confidencialidade: Proteção dos dados contra divulgação não autorizada. A informação só deve estar disponível para aqueles devidamente autorizados;
• Integridade: Proteção dos dados contra modificação não autorizada. A informação
não deve ser destruída ou comprometida e os sistemas devem ter um desempenho
correto;
• Disponibilidade: Proteção de acesso aos recursos da rede para que estejam disponíveis quando requisitados pelas entidades autorizadas. Os serviços e recursos do
sistema devem estar disponíveis sempre que forem necessários;
• Autenticidade: Proteção dos recursos da rede contra acesso não autorizado. É
necessário a identificação dos elementos da transação;
• Não-repúdio: Proteção contra negação falsa de ações que um usuário ou entidade
tenha feito. Não é possível negar a existência ou autoria de uma operação que criou,
modificou ou destruiu uma informação;
• Auditoria: Implica no registro das ações realizadas no sistema, identificando os sujeitos e recursos envolvidos, as operações realizadas, seus horários, locais e outros
dados relevantes.
Essas propriedades guiam para a determinação de um foco no qual uma determinada aplicação deve ser desenvolvida, a fim de atender os requisitos de segurança especificados pela própria necessidade do ambiente em questão. No entanto, não é apenas isto
que dita o escopo de uma aplicação para segurança de redes, sendo importante delimiar
a(s) fase(s) de proteção em que ela irá atuar.
3.3.1. Fases para Proteção de Redes
1
É possível destacar quatro fases para proteger a rede contra ataques [41]: Prevenção (Prevetion), Detecção (Detection), Defesa (Defense) e Forense (Forensics), como pode ser
visto na Figura 3.4. A prevenção compreende todos os métodos aplicados para evitar
ataques, a fim de garantir a confidencialidade e integridade dos dados, com a utilização de
controles de acesso aos recursos da rede. Isso inclui técnicas de autorização e autenticação (serviços de login), estabelecimento de confiança, bem como criptografia e filtragem
63
de tráfego (uso de firewall). É importate ressaltar que prevenção só é possível para ataques conhecidos, mas há trabalhos sendo desenvolvidos no sentido de prever a ocorrência
de ataques desconhecidos, como em [33] e [37].
Figura 3.4. Quatro fases de proteção [41].
1
Mecanismos de prevenção são considerados sistemas de defesa em primeira linha,
ou seja, são responsáveis pela primeira etapa na segurança de uma rede de computadores.
Normalmente essa defesa em primeira linha é feita na fase de projeto da rede, a fim de
desenvolvê-la já de maneira segura e obter melhores resultados quando colocada em operação. Esses mecanismos são tipicamente implantados para controlar acesso a recursos e
à informação que transita na rede.
Se a prevenção falhar, detecção é a próxima fase a lidar com um incidente. Detecção é então o processo de descoberta de um ataque ou da preparação para sua realização,
ou quaisquer outras atividades maliciosas, desde um port scan até indícios de quebra de
senhas por técnica de força bruta. Isso normalmente é feito pela análise de dados capturados por um sniffer, sendo este a interceptação e registro de dados que trafegam pela
rede.
Sistemas de detecção de intrusão (IDS - Intrusion Detection Systems) são utilizados na fase de detecção. Eles realizam o monitoramente da rede, chamado de NIDS
(Network Based Intrusion Detection System), ou de um dispositivo conectado a ela, bem
conhecido como HIDS (Host Based Intrusion Detection System), com objetivo de encontrar a ocorrência de algum ataque ou atividade maliciosa. Um IDS pode utilizar várias
abordagens para identificar um ataque, sendo as mais conhecidas: Baseado em Assinatura
(Signature Based) e Baseado em Anomalia (Anomaly Based), como descrito em [18]:
• Baseado em Assinatura: Monitora as atividades da rede, ou de um dispositivo
específico, procurando por ocorrências de alguma intrusão que é comparada com
uma base de assinaturas, esta última contendo informações de características de
ataques e atividades maliciosas;
• Baseado em Anomalia: Inicialmente é montado um perfil que representa o comportamento normal da rede ou host, fase conhecida como treinamento. Posteriormente o sistema entra em fase de monitoramento, no qual utiliza várias métricas
para determinar se está havendo algum comportamento diferente do perfil inicial,
caracterizando então uma intrusão.
64
Outro mecanismo encontrado na fase de detecção é visto através das chamadas
Metodologias de Decepção, definidas em [15] como a criação de um ambiente falso para
enganar usuários mal intencionados. Elas são usadas quando aplicadas técnicas no qual
o atacante interage com um recurso colocado como uma armadilha, propositalmente vulnerável, que emula os serviços ou sistemas que realmente deveriam ser alvos de sua ação.
Técnicas bastante utilizadas são com o uso de honeypots, definido por Spitzner [38] como
um recurso de rede cuja função é de ser sondado, atacado ou comprometido. Significa dizer que poderá ser invadido, sendo uma máquina configurada a fim de obter informações
sobre o invasor. A intenção é que o intruso ao realizar uma tentativa de invasão, na qual
a rede possua um honeypot em funcionamento, tenha a sensação de está interagindo com
uma máquina que exerce alguma funcionalidade e poderá conseguir algum recurso.
Se um tráfego malicioso é detectado, então é iniciado o processo ou fase de defesa.
Para que isso ocorra é necessário que o sistema implemente essas duas fases (detecção e
defesa), integrando mais de uma aplicação de segurança. Um exemplo é o Sistema de
Prevenção de Intrusão (IDS - Intrusion Prevention System), no qual gera alguma resposta
a fim de neutralizar o ataque, podendo integrar um IDS e um firewall, por exemplo.
Em alguns casos quando as fases anteriores de prevenção e detecção falham e
o ataque foi bem sucedido, se faz necessário uma análise de todos os logs, no sentido
de aprender como os métodos utilizados nos processos de detecção e defesa podem ser
melhorados para futuros incidentes. Sendo esta a fase chamada de forense, que tem
como objetivo realizar uma investigação para descobrir detalhes específicos de ataques,
apresentando resultados que contribuam de alguma maneira para a melhoria da proteção
da rede. Outro objetivo desta fase é fornecer provas suficientes para permitir que o autor
do incidente de segurança seja processado. Para Pilli ES et al., em [31], as técnicas de
forense de rede fornecem recursos para os investigadores rastrearem os atacantes.
Diante destas fases é possível caracterizar a atuação das aplicações de segurança
de redes. Por sua vez, muitas das aplicações utilizadas atualmente possuem problemas.
Junto a isso, os ataques à redes de computadores vem se tornando cada vez mais sofisticados. Esses problemas serão detalhados a seguir.
3.3.2. Problemas Enfrentados
1
Zseby et al., em [41], afirma que a segurança de redes necessita crucialmente de uma
maior atenção por parte do administrador e quase sempre de mais esforços e custos, pois
novos protocolos e aplicações introduzem novas vulnerabilidades. Infelizmente, os mecanismos utilizados para aumentar o nível de segurança atualmente possuem alguns problemas, a saber:
• Estrutura sólida: Sistemas desenvolvidos para segurança possuem pouca flexibilidade, pois são desenvolvidos apenas para situações isoladas. Não possuem as
características de um sistema aberto. Também não são capazes de se integrar com
outros mecanismos de segurança existentes no ambiente;
• Habilidade de defesa baixa: O escopo das atuais aplicações de segurança é limitado. São desenvolvidas apenas para atender alguma das fases de proteção, sem ter
65
a habilidade para prover um mecanismo integrado que forneça maior capacidade de
segurança;
• Sem autoadaptação: Aplicações não tem a capacidade de mudar componentes
internos para se adaptarem às necessidades do ambiente em que se encontram a fim
de conseguir provê segurança à rede. Todo um processo de reconfiguração manual
é preciso para manter a segurança;
• Sem autoaprendizagem: Aplicações não possuem a habilidade para aprender com
o tempo que se encontram em funcionamento, necessitando de intervenção para
se atualizarem. Não conseguem aprender com suas próprias ações, verificando os
resultados destas que foram providos à rede, para uma análise e melhorias futuras;
• Sem autoevolução: Além de não possuirem capacidade para aprenderem, ainda
não implementam meios para que novos conhecimentos sejam agregados às técnicas de defesa.
Para Atay e Masera, em [2], todos os métodos de análise de ameaças, vulnerabilidades e riscos necessitam atualizarem continuamente os seus conhecimentos sobre as
novas fraquezas encontradas nos ativos da rede. Isso servirá para identificar como estas
fraquezas podem ser exploradas, para posteriormente definir e aplicar as contramedidas
necessárias. Esse é um ciclo contínuo, pois novas avaliações serão necessárias ao longo
do tempo.
No entanto, sabe-se que informações sobre novos ataques não são imediatamente
divulgadas, pelos fabricantes ou pela comunidade que desenvolve o software, devido à sua
sensibilidade. Isso ocorre devido essas informações poderem ser utilizadas para explorar
mais ainda as vulnerabilidades, visto que usuários mal intecionados podem obtê-las. Elas
são publicadas então logo após os fabricantes liberarem as correções. Os métodos de
análise de riscos citado por [2] devem refazer a avaliação de segurança dos sistemas levando em consideração informações de novos ataques quando forem divulgadas, ou com
a utilização de técnicas de inteligência para detecção antes mesmo da divulgação.
Diante desta situação, Wang et al. [40] afirma que a direção correta para o desenvolvimento de aplicações de defesa e segurança é com a adoção de duas características: a
integração e inteligência. Integração para possibilitar o gerenciamento de vários recursos
de proteção em um ambiente de rede distribuído e a inteligência para provê adaptação
ao ambiente, aumentar a eficiência de proteção baseado em seu conhecimento e no que
adquiriu e, por fim, alcançar um equilíbrio entre a aplicação de segurança e o ambiente de
rede.
Aliado aos problemas enfrentados pelos atuais sistemas de segurança, os ataques
a sistemas computacionais estão se tornando cada vez mais sofisticados, imprevisíveis,
frequentes e com uma maior quantidade de origens [2]. Como exemplo destes ataques
pode-se destacar os realizados com a utilização de Botnets e os ataques de último dia,
detalhados a seguir.
66
3.3.2.1. Botnets
1
De acordo com Rajab et al., em [35], Botnet é uma rede de computadores comprometidos controlados remotamente por um operador humano chamado de botmaster. Um bot
é uma aplicação residente em um nó integrante de uma Botnet com capacidade de se
autopropagar infectando outros hosts vulneráveis.
Botnets são plataformas de computação distribuída predominantemente usadas
para atividades ilegais com o objetivo de lançamentos de ataques de negação de serviço distribuído (DDoS - Distributed Denial of Service), envio de spam, trojan e e-mails
phishing, distribuição ilegal de mídias e softwares piratas, roubo de informações e de
recursos computacionais, realização de fraudes e falsidade de identidade [7].
3.3.2.2. Ataques de Último Dia
1
Um ataque de último dia, do inglês Zero-day Attack ou 0-Day Attack, também conhecido
como ataque de dia zero ou zero hora, aproveita vulnerabilidades que atualmente não tem
uma solução ou ainda não são conhecidas [33] [37]. Normalmente, é descoberto um bug
ou um problema em um software depois que ele foi liberado, sendo então em seguida
oferecida uma correção destinada ao problema original. Um ataque de último dia vai
aproveitar esse problema antes da correção ser criada. Na maioria dos casos, esse tipo
de ataque vai tirar proveito de um problema não conhecido pelos criadores do software e
seus usuários.
É importante ressaltar que nem todos os ataques de último dia realmente acontecem antes dos produtores de software estarem cientes da vulnerabilidade. Em alguns
casos eles conhecem a vulnerabilidade, mas o desenvolvimento da correção pode demandar um tempo elevado, em frente a complexidade do problema enfrentado. Neste sentido,
proteção de último dia é a capacidade de um sistema de segurança fornecer proteção contra ataques de último dia.
3.4. Segurança Autonômica em Redes de Computadores
1
Os sistemas de proteção das redes atuais estão baseados no paradigma da computação
interativa, ou seja, fica a cargo dos administradores humanos decidirem o que fazer e
como proteger os sistemas no caso de ocorrências de ataques maliciosos ou erros em
cascata imprevistos [3]. Os sistemas que incorporam mais de uma fase para proteção de
rede, objetivando aumentar ainda mais o nível de segurança, são mais complexos. Isso se
deve ao fato de possuirem mais componentes para atenderem os requisitos de cada fase.
Essa complexidade necessita de uma constante intervenção humana especializada para a
correta utilização do sistema.
Dessa maneira, é interessante a utilização de mecanismos autonômicos para automatizar os processos de gerência. A aplicação dos conceitos da CA à segurança de redes
introduz no sistema a capacidade de autosegurança, através da qual serviços e funções de
gerenciamento da segurança são executados sem a necessidade de um gerente humano, a
partir da definição de objetivos e parâmetros iniciais fornecidos por seus administradores.
67
É possível destacar também que para tentar propror soluções aos problemas descritos anteriormente (Seção 1.3.2), a arquitetura de sistemas autonômicos pode ser aplicada para o desenvolvimento de software voltado para defesa e segurança. O modelo
MAPE-K (Seção 1.2.2.1) oferece uma visão conceitual de como sistemas autonômicos
podem ser desenvolvidos para atender necessidades de segurança.
Sensores podem ser qualquer programa que verifique ocorrências de tráfego malicioso, independente de qual fase de proteção seja, coletando informações relevantes da
rede para serem enviadas aos monitores. Exemplo de dados coletados podem ser, por
exemplo, o tráfego destinado a honeypots, alertas de IDS, logs de firewall, etc. Os monitores irão receber essas informações e tratá-las a fim de extrair o que vem a ser relevante,
por exemplo, o endereço ip de origem do intruso, o protocolo utilizado pelo serviço no
qual foi realizado o ataque, horário/data da intrusão, etc.
Os monitores enviarão as informações necessárias para os componentes de análise
e planejamento, que as utilizarão para seu processamento. Como se sabe, geralmente as
fases de análise e planejamento são implementadas em um único componente. O processamento realizado por esse componente varia de acordo com a estratégia autonômica
adotada pelo administrador que inseriu os objetivos para o sistema. Um exemplo de processamento utilizando ECA rules pode ser visto na Figura 3.5. Neste exemplo, na ocorrência de um alerta de IDS (IDSAlert), se o IP de origem que gerou o alerta não estiver na
lista negra do firewall (BlackList !Contains SrcIpAddr), será adicionado (Add SrcIpAddr
in BlackList).
on IDSAlert if BlackList !Contains SrcIpAddr do Add SrcIpAddr in BlackList;
Figura 3.5. Exemplo de reconfiguração.
1
A base de conhecimento pode ser utilizada pelo componente de análise e planejamento na adoção de estratégias para, por exemplo, não realizar ações anteriormente já
feitas. Na Figura 3.5 não serão adicionados endereços IP na lista negra que já estiverem
contidos. O componente de análise e planejamento terá como saída um plano de ação a
ser executado pelo componente executor, que na Figura 3.5 é a adição do endereço IP de
origem que gerou o alerta na lista negra.
O executor irá aplicar as ações no elemento gerenciado através dos atuadores. Atuadores são responsáveis por fazerem alterações de configuração no elemento gerenciado,
ou seja, em alguma aplicação de segurança da rede. O objetivo em realizar as mudanças
nas configurações é aumentar o nível de segurança. No exemplo da Figura 3.5 o atuador
irá interagir diretamente com a aplicação responsábel pela lista negra, o firewall.
Além da arquitetura de sistemas oferecida pela CA, visando o estado em que se encontram os atuais sistemas de segurança e também o crescimento e evolução dos ataques
às redes de computadores, é possível relacionar a necessidade que este tipo de sistema
tem pelas propriedades dos sistemas autonômicos, destacando as propriedades de autoproteção (self-protecting), autocura (self-healing), autoconfiguração (self-configuring) e
autoaprendizagem (self-learning) [30], como visto a seguir.
68
• Autoproteção: Refere-se à propriedade do sistema de defender-se de ataques acidentais ou maliciosos. Para tanto, o sistema deve ter conhecimento sobre potenciais
ameaças, bem como provê mecanismos para tratá-las [5]. Para atingir essa propriedade o sistema deve ter habilidade para antecipar, detectar, identificar e proteger o
elemento gerenciado contra ameaças;
• Autocura: Responsável por identificar e corrigir erros ou falhas. No contexto da
segurança de redes, o sistema autonômico deve ser capaz de detectar, diagnosticar
e consertar problemas resultantes de ataques a ativos de produção da rede. Utilizando conhecimento sobre a configuração dos recursos da rede, o sistema deve
possuir um componente de diagnóstico que deve analisar informações que mostram
a ocorrência de falhas ou danos causados por um ataque à rede, para posteriormente
buscar uma solução a ser tomada, aplicá-la e depois testar se foi satisfatória. Essa
solução poderá ser, por exemplo, a substituição dinâmica de recursos por suas réplicas. É importante ressaltar que o processo de cura deve ser realizado com máxima
transparência para usuários legítimos da rede;
• Autoconfiguração: Nesta propriedade é fornecido a capacidade para os sistemas se
configurarem e reconfigurarem automaticamente de acordo com políticas de negócio fornecidas por seus administradores, os quais definem o que deve ser feito e não
como fazer [5]. A fim de automatizar o gerenciamento de configuração, um sistema
de segurança deve possuir capacidade de reconfiguração dinâmica com o mínimo
de intervenção humana;
• Autoaprendizagem: Propriedade que fornece capacidade de aprendizado a partir
de dados sensoriados e também através de experiências e resultados obtidos em
ações anteriores. Propriedade fundamental para sistemas de segurança, visto que
ela oferece a capacidade para o sistema aprender a se defender de ataques antes
desconhecidos, ou, pelo menos, reconhecer tráfego malicioso na rede para posterior defesa. Um exemplo pode ser visto no trabalho desenvolvido em [32] (Seção
1.4.1.5), no qual é atualizado a base de assinaturas de um IDS quando são descobertos novos ataques.
Mesmo diante de várias qualidades oferecidas pela CA, aplicá-la às redes de computadores e sua segurança não é um processo trivial, há desafios a serem enfrentados para
alcançar o autogerenciamento. Segundo Agoulmine et al., em [1], o desafio é simplificar as tarefas de gerência para o administrador, automatizando o processo de decisão.
Questões de segurança é outro desafio para o desenvolvimento de sistemas autonômicos,
visto que o emprego de autoaprendizagem e autoevolução poderá ocasionar a perda do
domínio humano sob a gerência das decisões tomadas pelo próprio sistema, havendo a
possibillidade de desvio dos objetivos iniciais inseridos. Com isso, no processo de desenvolvimento de software autonômico a fase de validação deve ser aplicada de maneira
rigorosa.
3.4.1. Sistemas de Segurança baseados em Computação Autonômica
1
Para dar uma visão com mais alto grau de realismo, serão vistos alguns trabalhos que
utilizam a CA como base para o desenvolvimento de suas propostas ou implementam
69
alguma das propriedades oferecidas pela CA. Inicialmente será mostrado exemplos de
sistemas que tem fundamentação na CA ou que fornecem algumas propriedades da CA.
3.4.1.1. ISDS
1
Em [40] foi desenvolvido o ISDS (Intelligent Security Defensive Software), um modelo
de software de segurança baseado em CA. A estratégia do ISDS é fazer o processo de
construção do software de segurança fornecendo a ele inteligência. Em outras palavras,
construir um software utilizando o modelo ISDS é fazer com que seus componentes se
modifiquem dinamicamente de acordo com a situação de segurança atual da rede. Para
isto, o ISDS fornece consciência do contexto.
O ISDS é um modelo de sistema de defesa distribuído caracterizado por ser flexível e autoadaptativo. Os domínios nos quais ele pode ser aplicado são principalmente no
gerenciamento de segurança em redes locais e na gerência de segurança da informação na
Internet. A ideia do modelo é que o sistema possa analisar as informações do ambiente
e ajustar sua estrutura e maneira de agir dinamicamente. Ele consiste de alguns componentes básicos, são eles: componente de comando, componente de execução, componente
sensor, componente de políticas, componente de equipamento e outros auxiliares como
visto na Figura 3.6.
Figura 3.6. Framework conceitual do ISDS [40].
1
O componente de comando é a principal parte do ISDS, tendo como funções: a
ativação dos componentes de políticas, sensor e equipamento, a execução da tomada de
decião baseada no componente sensor, o gerenciamento do conjunto de componentes de
segurança e política, atualização de novos componentes de segurança e políticas, verificando e resolvendo conflitos de políticas. Já o componente de execução trabalha como um
canal de comunicação entre as entidades de segurança e o componente de comando. Ele
se encarrega de filtrar, tratar e transmitir a mensagem para todos os outros componentes,
os fazendo trabalharem corretamente.
70
O componente de políticas se encarrega principalmente em fazer a manutenção do
conjunto de políticas, a tomada de decisão das políticas adequadas e também a passagem
do resultado da decisão. As informações do resultado das decisões tomadas serão passadas para o componente de equipamento que então irá executar alguma ação. Por fim,
o componente sensor coleta informações do ambiente e as envia para o componente de
comando, levando em consideração o custo do sensoriamento de dois modos: emergência
e timing, sendo o primeiro com maior prioridade em relação ao segundo.
3.4.1.2. Autonomic Security and Self-Protection based on Feature-Recognition with
Virtual Neurons
1
No trabalho desenvolvido em [6] foi apresentado um mecanismo de segurança autonômico baseado em neurônios virtuais e no reconhecimento de características. Sua abordagem trabalha para detectar automaticamente vários problemas de segurança que atualmente são difíceis de realizar defesa. Através de simulação e diferentes estudos de caso,
resultados mostram que esta solução é viável.
Os neurônios virtuais são desenvolvidos de forma análoga aos neurônios dos animais, como visto na Figura 3.7. A ideia é que eles sejam distribuídos de maneira a perceber modificações no ambiente e reagir a estímulos. Esse neurônio virtual é na realidade
um simples software com capacidade de ciência de contexto, a fim de analisar informações do contexto e estar ciente de eventuais surgimentos de ataques.
Figura 3.7. Neurônio Virtual [6].
1
No neurônio virtual, o componente Information Collector captura várias informações de contexto, tais como uso de memória e processador, status dos processos e
informações de tráfego da rede. São considerados vizinhos os neurônios que se conectam
diretamente, através do Neighbor Communicator. Existe um outro componente chamado
de Feature Recognizer, seu funcionamento é baseado no conhecimento sobre infomações
que caracterizam um ataque (baseado em assinaturas). Essas informações são passados
para o Feature Recognizer pelo Information Collector do próprio neurônio e dos seus vizinhos, através do Neighbor Communicator. Os neurônios virtuais podem ser facilmente
distribuídos, pois o pacote de instalação é compacto (tamanho pequeno), eles exigem
poucos recursos computacionais e são de fácil instalação nos hosts.
71
Esses neurônios virtuais são distribuídos em uma arquitetura hierárquica e Par-apar (P2P - Peer-to-peer), como visto na Figura 3.8. A estrutura P2P opera baseada nas
relações com neurônios vizinhos, tendo a comunicação entre eles através de passagem de
mensagens. A arquitetura hierárquica é utilizada para aumentar a eficiência na propagação
das mensagens por grupo de neurônios, chamados de células. Em cada célula um neurônio
é eleito como neurônio-chefe, o algoritmo de eleição leva em consideração os recursos
computacionais e velocidade de comunicação do host.
Figura 3.8. Estrutura de organização hierarquica e P2P dos neurônios virtuais [6].
1
Na organização hierárquica, um neurônio-chefe é eleito como o chefe de alto nível
para outros neurônios-chefes. Este procedimento é repetido até existir um único neurôniochefe de maior nível sobre os demais. Se ocorrer alguma falha em algum neurônio-chefe
de uma célula, um outro neurônio desta mesma célula irá assumir o papel de neurôniochefe, através de uma nova eleição. Nessa organização hierárquica as mensagens são
entregues de maneira mais eficiente.
O mecanismo de segurança empregado por este sistema distribuído é feito na detecção de mensagens com dados ou mensagens ilegais. Primeiramente as origens dos
ataques são rastreadas para identificar e localizar o atacante. Depois o tráfego ilegal originado por ele é bloqueado, ou seja, todos os neurônios irão receber mensagens para
descartarem tráfego que tenha como origem um usuário malicioso identificado. A reconfiguração de recursos é feita neste momento para realização da defesa pelo sistema. Para
realizar a detecção e posterior defesa foi desenvolvido um mecanismo (característica ou
assinatura) para cada tipo de ataque, dentre esses: Eavesdropping, Replay, Masquerading,
Spoofing e Negação de Serviço (DoS - Denial of Service).
3.4.1.3. Self-Configuration of Network Security
1
Este trababalho [4] apresenta uma abordagem de autoconfiguração para controlar e gerenciar os mecanismos de segurança em redes de grande porte. Nela o sistema automaticamente configura os mecanismos de segurança e modifica as configurações dos recursos
e suas políticas em tempo de execução. Para mostrar sua viabilidade foi implementado
o AND (Autonomic Network Defense System). AND é um sistema que pode detectar
ataques de rede conhecidos ou desconhecidos (ataques de último dia) e proativamente
prevenir ou minimizar impactos causados em serviços da rede.
72
O AND foi desenvolvido sobre o framework AUTONOMIA [13], sendo uma extensão focada em estratégias e mecanismos para detectar e proteger-se de ataques de rede.
O AUTONOMIA possui dois módulos de software, são eles: Component Management Interface (CMI) e Component Runtime Manager (CRM). O CMI é utilizado para especificar
as configurações e políticas associadas com cada componente (de hardware ou software).
E o CRM que gerencia as operações dos componentes usando as políticas definidas no
CMI. Mais detalhes sobre o framework AUTONOMIA podem serem vistos em [14].
As principais extensões do AND são os módulos de Monitoramento Online (Online Monitoring), Seleção de Característica (Feature Selection), Análise de Anomalia
(Anomaly Analysis) e o de Ação (Action Module), como visto na Figura 3.9. É possível observar que essa arquiteura é baseada no MAPE-K.
Figura 3.9. Arquitetura do AND [4].
1
O monitoramento online coleta os dados trafegados na rede e operações realizadas em computadores através de ferramentas específicas e arquivos de log gerados por
sistemas operacionais. O modelo de seleção de característica irá filtrar os dados monitorados a fim de encontrar informações ou características relevantes para serem passadas
para o módulo seguinte. No módulo de análise de anomalias é executada uma função
para quantificar se existe um desvio do perfil padrão da rede ou de algum sistema, caso
haja, é considerado uma anomalia e o módulo de ação irá executar ações adequadas. O
módulo de ação irá, resumidamente, restringir o acesso aos recursos atacados e posteriosmente tentar desinstalar códigos maliciosos que estão executando em computadores
comprometidos da rede.
3.4.1.4. Qualidade de Proteção
1
Trabalho iniciado em [10] teve como resultado um novo termo em [12] chamado de Qualidade de Proteção (QoP - Quality-of-Protection). Ele é um framework proativo para
defesa de redes que pode ser integrado com os já existentes protocolos de Qualidade de
Serviço (QoS - Quality-of-Service). O objetivo é provê serviços diferenciados para fluxos
de tráfegos de acordo com seu grau de anormalidade.
Para isso foi criado uma nova métrica chamada de Distância de Anormalidade
(DA), como visto na Figura 3.10, que pode ser usada para classificar o tráfego em normal, incerto (tráfego suspeito) e anormal (tráfego malicioso). Existe uma função Delta
73
que mostra o quanto mais próximo o tráfego está de normal ou anormal, podendo ser
classificado então como provavelmente normal ou provavelmente anormal.
Figura 3.10. Distância de Anormalidade [10].
1
A ideia é que a métrica AD seja usada em conjunto com protocolos de QoS para
aumentar a prioridade de tráfegos considerados normais e diminuir a prioridade de tráfegos anormais. Testes foram realizados com ataques de DDoS e propagação de Worms.
Com isso foi possível demonstrar o quanto a abordagem proposta pode detectar e reduzir
o impacto causado pelos ataques.
3.4.1.5. Propriedades de Computação Autonômica em Sistemas de Segurança
1
Alguns trabalhos se cacterizam por fornecer alguma(s) das propriedades autonômicas de
maneira isolada, mesmo não tendo como base a CA. Ou seja, foram desenvolvidos sem
seguir os conceitos da CA, mas provem algum mecanismo que se qualifica dentre alguma
das propriedades autonômicas. Sistemas como estes não são considerados autonômicos.
Foi desenvolvido em [39] um esquema de segurança para atualização de regras
de firewall baseado no tráfego de uma honeynet (autoconfiguração e autoaprendizagem).
Para [38] honeynets são múltiplos honeypots juntamente com um firewall para limitação
e log de tráfego. No esquema há um módulo de análise de dados que oportunamente
descobre novos ataques. Este módulo analisa o tráfego gerado pelos logs da honeynet e
com a utilização de mineração de dados ele cria dinamicamente novas regras de firewall
passando-as para o módulo de aprendizagem de regras, que as filtra eliminando incoerências entre as regras e, por fim, ele as aplica. Dessa maneira o firewall continua enriquecendo suas estratégias melhorando sua capacidade para se defender de novos ataques,
inclusive ataques de último dia.
A ferramenta Honeycomb [21] tem como objetivo automatizar a geração de assinaturas de ataques para sistemas de detecção de intrusão a partir de logs gerados por
honeypots (autoaprendizagem). Na verdade esta ferramenta trata-se de um plugin a ser
utilizado junto ao honeyd [34], que é um framework de honeypots de baixa interatividade
[38]. A implementação do Honeycomb gera assinaturas no formato Bro [29] e Snort [36].
Sua intenção é ser utilizado para criar as assinaturas de ataques em tempo de execução
74
(autoconfiguração), atividade que normalmente é realizada manualmente por especialistas
de segurança após o registro das atividades maliciosas nos logs.
No caso do SweetBait [32], foi desenvolvido um sistema automatizado de proteção que utiliza honeypots de baixa e alta interatividade para reconhecer e capturar tráfego
malicioso. Com base nos logs gerados, após descartar padrões da lista branca, ele automaticamente cria assinaturas de ataques (autoaprendizagem), componente implementado
utilizando o Honeycomb. Para provê um baixo tempo de resposta ao ataque ele distribui
imediatamente assinaturas para IDS’s (autoconfiguração), após sua geração. Paralelamente a isto, as assinaturas são refinadas continuamente a fim de aumentar sua precisão
e diminuir falsos positivos (auto-otimização). Este trabalho é extendido e surge então o
Argos [33] que emprega uma característica mais ampla, a propriedade de autoproteção,
por reagir proativamente contra ataques.
3.5. Conclusão
1
Em 2001 a IBM produziu um manifesto no qual alertou a dificuldade de gerenciamento
dos sistemas computacionais atuais e apontou a autonomia dos sistemas como a alternativa para a solução deste problema. Neste capítulo foi apresentado a definição e as
principais características de uma nova abordagem para o desenvolvimento de sistemas
que provem autonomia, a Computação Autonômica. Na qual envolve uma mudança no
modo de projetar sistemas computacionais.
A ideia por traz dessa abordagem é desenvolver software autogerenciável, tendo
pouca ou nenhuma intervenção humana para manter-se, baseado apenas em políticas de
alto nível definidas pelo supervisor e no conhecimento adquirido ao longo do tempo.
Uma série de propriedades autonômicas são utilizadas por esta abordagem para diminuir
ou eliminar a intervenção humana sob a gerência dos sistemas computacionais, tais como:
autocura, autoproteção, auto-otimização, autoaprendizagem, autoconfiguração, etc. Neste
sentido será colocado sob responsabilidade das próprias máquinas a tarefa de gerenciamento.
Foi mostrado também neste capítulo que as redes de computadores são cenários
onde a CA pode ser facilmente aplicada, principalmente pelo crescimento resultante da
Internet. Em particular, apresentou-se a aplicabilidade de CA em um ambiente bem específico, a gerência da segurança de redes. Para isto foi explicitado a necessidade da segurança de redes por mecanismos autonômicos e maneiras de como é possível implementálos. Trabalhos já realizados dentro da temática foram descritos a fim de oferecer uma
visão mais prática.
Finalizando, pesquisas mostram que a direção correta para as aplicações de segurança é a adoção de integração e inteligência, então isso mostra que os recursos fornecidos
pela CA é o caminho mais viável para solucionar problemas existentes nas redes de computadores e de maneira mais específica, como visto, na segurança destas.
Agradecimento: O desenvolvimento deste trabalho foi viabilizado pelo apoio
financeiro concedido pela Fundação de Amparo à Pesquisa e ao Desenvolvimento Científico e Tecnológico do Maranhão (FAPEMA).
75
Referências
[1] Agoulmine, N., Balasubramaniam, S., Botvich, D., Strassner, J., Lehtihet, E. e Donnelly, W. (2006), “Challenges for Autonomic Network Management”, In 1st IEEE
International Workshop on Modelling Autonomic Communications Environments MACE.
[2] Atay, S. e Masera, M. (2009), “Challenges for the security analysis of Next Generation Networks”, In Proceedings of the Sixth International Conference on Broadband
Communications, Networks, and Systems - BROADNETS.
[3] Braga, T. R. M., Silva, F. A., Ruiz, L. B., and ao, H. P. A. (2006), “Redes Autonômicas”, In XXIV Simpósio Brasileiro de Redes de Computadores e Sistemas
Distribuídos - SBRC, Sociedade Brasileira de Computação (SBC).
[4] Chen, H., Al-Nashif, Youssif B., Qu, G. e Hariri, S. (2007), “Self-Configuration of
Network Security”, In Proceedings of the 11th IEEE International Enterprise Distributed Object Computing Conference, p. 97-108.
[5] Corrêa, S. e Cerqueira, R. (2009), “Computação Autônoma: Conceitos, Infraestruturas e Soluções em Sistemas Distribuídos”, In XXVII Simpósio Brasileiro de
Redes de Computadores e Sistemas Distribuídos - SBRC, Sociedade Brasileira de
Computação (SBC).
[6] Dai, Y., Hinchey, M., Qi, M. e Zou, X. (2006), “Autonomic Security and SelfProtection based on Feature-Recognition with Virtual Neurons”, In Proceedings
of the 2nd IEEE International Symposium on Dependable, Autonomic and Secure
Computing.
[7] Feily, M., Shahrestani, A. e Ramadass, S. (2009), “A Survey of Botnet and Botnet
Detection”, In Third International Conference on Emerging Security Information,
Systems and Technologies.
[8] Gonçalves, J. F. (2010), “Introdução à Computação Autonômica e sua Aplicação em
Ambientes Computacionais Distribuídos”, Graduate thesis, Universidade Federal do
Maranhão, Bacharelado em Ciência da Computação.
[9] Goodloe, A. e Pike, L. (2010), “Monitoring distributed real-time systems: A survey
and future directions”, NASA Langley Research Center.
[10] Guangzhi Qu, Hariri, S., Jangiti, S., Rudraraju, J., Seungchan Oh, Fayssal, S.,
Guangsen Z. e Parashar, M. (2004), “Online Monitoring and Analysis for SelfProtection against Network Attacks”, In Proceedings of the International Conference
on Autonomic Computing, p. 324-325.
[11] Hallsteinsen, S. (2010), “Madam-theory of adaptation”, Technical report, SINTEF
ICT.
[12] Hariri, S., Guangzhi Qu, Modukuri, R., Chen, H. e Yousif, M. (2005), “Quality-ofProtection (QoP) - An Online Monitoring and Self-Protection Mechanism”, IEEE
Journal on Selected Areas in Communications, v. 23, n. 10, p. 1983-1993.
76
[13] Hariri, S., Khargharia, B., Chen, H., Yang, J., Zhang, Y., Parashar, M. e Liu, H.
(2006), “The autonomic computing paradigm”, Cluster Computing, Springer, v. 9,
p. 5-17.
[14] Hariri S., Xue L., Chen, H., Zhang, M., Pavuluri, S. e Rao, S. (2003), “AUTONOMIA: an autonomic computing environment”, In Proceedings of the IEEE International Performance, Computing, and Communications Conference, p. 61-68.
[15] Hongli, Z. e Qassrawi, Mahmound T. (2010), “Deception Methodology in Virtual
Honeypots”, In Second International Conference on Networks Security, Wireless
Communications and Trusted Computing, Wuhan, China, p. 462-467.
[16] Huebscher, Markus C. e McCann, Julie A. (2008), “A survey of autonomic computing - degrees, models, and applications”, ACM Computing Surveys, v. 40, n. 3.
[17] IBM (2003), “An architectural blueprint for autonomic computing”, IBM Press
Prentice-Hall.
[18] Kabiri, P. e Ghorbani, Ali A. (2005), “Research on Intrusion Detection and Response: A Survey”, International Journal of Network Security, v. 2, n. 1, p. 84-102.
[19] Kephart, J.O. e Chess, D.M. (2003), “The Vision of autonomic computing”, Computer, IEEE Computer Society, p. 41-50.
[20] Krause, M. and Tipton, H. F. (1999), “Handbook of Information Security Management”, Auerbach Publications, http://www.cccure.org/Documents/HISM/.
[21] Kreibich, C. e Crowcroft, J. (2004), “Honeycomb - Creating Intrusion Detection Signatures Using Honeypots”, SIGCOMM Computer Communication Review, ACM,
v. 34, ed. 1.
[22] Léger, M., Ledoux, T. e Coupaye, T. (2007), “Reliable dynamic reconfigurations in
the fractal component model”, In Proceedings of the 6th international workshop on
adaptive and reflective middleware: held at the ACM/IFIP/USENIX International
Middleware Conference - ARM, New York, NY, USA, p. 1-6.
[23] Mansouri-samani, M. (1995), “Monitoring of Distributed Systems”, PhD thesis,
University of London, Imperial College of Science, Technology and Medicine.
[24] McKinley, P. K., Sadjadi, S. M., Kasten, E. P. e Cheng, B. H. C. (2004), “Composing
adaptive software”, IEEE Computer Society, p. 56-64.
[25] Murch, R. (2004), “Autonomic computing”, IBM Press Prentice-Hall.
[26] Palma, N. D., Laumay, D. P. e Bellissard, L. (2001), “Ensuring dynamic reconfiguration consistency”, In 6th International Workshop on Component-Oriented Programming - WCOP, p. 18-24.
[27] Parashar, M. e Hariri, S. (2005), “Autonomic computing: An overview”, Unconventional Programming Paradigms, Springer Verlag, p. 247-259.
77
[28] Parashar, M. e Hariri, S. (2007), “Autonomic computing: concepts, infrastructure,
and applications”, CRC Press.
[29] Paxson, V. (1999), “Bro: A System for Detecting Network Intruders in Real-Time”,
Computer Networks, v. 31, n. 23-24, p. 2435-2463.
[30] Poslad, S. (2009), “Autonomous Systems and Artificial Life”, Ubiquitous Computing: Smart Devices, Environments and Interactions, John Wiley & Sons, Ltd., p.
317-341.
[31] Pilli, E. S., Joshi, R.C. e Niyogi, R. (2010), “Network forensic frameworks: Survey
and research challenges”, Digital Investigation, Elsevier, p. 1-14.
[32] Portokalidis, G. e Bos, H. (2007), “SweetBait: Zero-hour worm detection and containment using low- and high-interaction honeypots”, Computer Networks, Elsevier,
v. 51, ed. 5, p. 1256-1274.
[33] Portokalidis, G., Slowinska, A. e Bos, H. (2006), “Argos: an Emulator for Fingerprinting Zero-Day Attacks for advertised honeypots with automatic signature generation”, In Proceedings of the EuroSys, p. 15-27.
[34] Provos, N. (2004), “A virtual honeypot framework”, In Proceedings of the 13th conference on USENIX Security Symposium, v. 13, Berkeley, CA, USA.
[35] Rajab, M., Zarfoss, J., Monrose, F. e Terzis, A. (2006), “A multifaceted approach to
understanding the botnet phenomenon”, In Proceedings of the 6th ACM SIGCOMM
Conference on Internet Measurement - IMC, p. 41-52.
[36] Roesch, M. (1999), “Snort: Lightweight Intrusion Detection for Networks”, In Proceedings of the 13th Conference on Systems Administration, p. 229-238.
[37] Song, J., Kwon, Y. e Takakura, H. (2008), “ A Generalized Feature Extraction
Scheme to Detect 0-Day Attacks via IDS Alerts”, In International Symposium on
Applications and the Internet - SAINT, Turku, Finlândia.
[38] Spitzner, L. (2002), “Honeypots: Definitions and Value of Honeypots”, SANS Annual Conference.
[39] Wang, B., Zhu, P., Wen, Q. e Yu, X. (2009), “A Honeynet-based Firewall Scheme
with Initiative Security Strategies”, In International Symposium on Computer
Network and Multimedia Technology - CNMT, p. 1-4.
[40] Wang, K., Wang, J., Shen, L. e Han, Z. (2010), “An Intelligent Security Defensive
Software Scheme and Realization”, In Third International Symposium on Intelligent
Information Technology and Security Informatics - IITSI, p. 793-796.
[41] Zseby, T. Pfeffer, H. e Steglich, S. (2009), “Concepts for Self-Protection”, Autonomic Computing and Networking, Springer Science, p. 355-380.
78
Capítulo
4
Linked Data: da Web de Documentos para a
Web de Dados
Danusa R. B. Cunha, Bernadette F. Lóscio, Damires Souza
Abstract
The term Linked Data refers to a set of best practices for publishing and connecting
structured data on the Web with the purpose of creating a Web of Data. Recently, a
significant number of datasets have been published adhering to the Linked Data
principles and numerous efforts are underway to build applications for exploit this
Web of Data. In this context, during this course, we present the fundamental
concepts of Linked Data, as well as the theoretical basis of how to publish and to
consume data available on the Web of Data. We also present some applications for
visualization and consume of Linked Data and we discuss the main difficulties and
challenges in this research area.
Resumo
O termo Linked Data refere-se a um conjunto de práticas para publicar e conectar
dados estruturados na Web, com o intuito de criar uma “Web de Dados”.
Recentemente, um grande volume de dados definidos de acordo com o padrão Linked
Data tem sido publicado, com isso, muitos esforços estão sendo feitos para construir
aplicações com o objetivo de facilitar a exploração de tais dados. Neste cenário, este
minicurso apresenta os conceitos relacionados ao termo Linked Data, bem como
provê aos participantes um embasamento prático de como publicar e consumir
dados na Web de Dados. Além disso, são apresentadas as aplicações usadas para
visualização e consumo dos dados Linked Data e, por fim, discute as principais
dificuldades e desafios nessa área de pesquisa.
79
4.1 Introdução
A Internet contemporânea, nos moldes da World Wide Web, vive um constante
processo de evolução e tem revolucionado a forma como criamos conteúdo e
trocamos informações. A Web organiza as informações disponíveis na Internet por
meio de hipertexto e torna a interação do usuário com a rede mundial mais amigável.
Com isso, possibilita um ambiente de compartilhamento de documentos oriundos de
diversas áreas do conhecimento. Entretanto, tais conteúdos geralmente seguem regras
apenas sintáticas, com objetivos de apresentação, não permitindo que se consiga
facilmente extrair semântica dos mesmos, sem que para isso seja feito um grande
esforço de implementação. Considerando isso, a Web atual pode ser classificada
como sintática e o processo de interpretação dos conteúdos disponibilizados fica
geralmente a cargo dos usuários [Costa & Yamate 2009].
Em sua maior parte, os dados na Web ainda são organizados para serem lidos
ou compreendidos por humanos e não por agentes de software. Para que um agente
de software possa entender e interpretar um dado, é necessário processar a semântica
envolvida naquele dado, num determinado contexto. Neste escopo, semântica diz
respeito à atribuição de significado a elementos, dados ou expressões que precisam
ser interpretados numa dada situação [Souza 2009]. No cenário da Web, isso
representa atribuir significado aos dados interligando-os com outros conjuntos de
dados ou outros domínios de conhecimento, conseguindo, assim, criar uma relação
de significância entre os conteúdos publicados na Internet de modo que seja
perceptível tanto pelo usuário quanto pelos agentes de software. Essa nova visão da
Web vem sendo denominada de Web Semântica (Semantic Web) [Lee et al. 2001].
A Web Semântica é considerada uma extensão da Web atual cujo objetivo
principal é facilitar a interpretação e integração dos dados na Web. Como parte do
desenvolvimento da Web Semântica, surgiu o conceito de Linked Data (dados
ligados) que pode ser definido como um conjunto de boas práticas para publicar e
conectar conjuntos de dados estruturados na Web, com o intuito de criar uma “Web
de Dados” [Bizer et al. 2009]. Estas práticas são fundamentadas em tecnologias
Web, como HTTP (Hypertext Transfer Protocol) e URI (Uniform Resource
Identifier), com o objetivo de permitir a leitura dos dados conectados
semanticamente, de forma automática, por agentes de software. A Web de Dados
cria inúmeras oportunidades para a integração semântica de dados, motivando o
desenvolvimento de novos tipos de aplicações e ferramentas, como navegadores e
motores de busca.
Este capítulo apresenta os conceitos básicos para publicação e consumo de
dados na Web de acordo com os padrões de Linked Data e está organizado como
segue. A seção 2 traça um paralelo entre a Web clássica e a Web de Dados. A Seção
3 apresenta uma visão geral sobre o tema Linked Data, introduzindo os princípios
que regem esse conjunto de práticas. Além disso, são explicados os seguintes
aspectos: (i) a nomeação de recursos através de URIs; (ii) como é possível utilizar
URIs para prover navegação entre os recursos; (iii) como disponibilizar os dados
através do modelo RDF, mostrando os benefícios oriundos desse modelo e (iv) como
links entre os recursos são criados e identificados. A Seção 4 discute os aspectos
básicos que devem ser considerados para a publicação de dados segundo os
80
princípios do Linked Data. Para tal, aborda questões de formatação e estruturação de
dados e, por fim, apresenta um conjunto de padrões e diretrizes a serem seguidos
com o intuito de tornar possível a publicação e interligação dos dados. A Seção 5
apresenta exemplos de aplicações existentes e, finalmente, a Seção 6 tece
considerações sobre o tema exposto, apontando benefícios de seu uso e dificuldades
ainda existentes.
4.2. Web de Documentos versus Web de Dados
Para um melhor entendimento sobre a Web de Dados, pode-se estabelecer um
paralelo entre a Web de Documentos (a Web atual) e a Web de Dados. A primeira
faz uso de navegadores HTML (HyperText Markup Language) para acessar dados na
enquanto que na segunda os dados são acessados a partir de navegadores RDF. Na
Web de Documentos hiperlinks são usados para navegar entre as páginas, enquanto
que na Web de Dados os links RDF são usados para acessar dados de diversas fontes.
A Web de Documentos é baseada em um conjunto de padrões, incluindo:
um mecanismo de identificação global e único, as URIs; um mecanismo de acesso
universal, o HTTP e um formato padrão para representação de conteúdo, o HTML.
De modo semelhante, a Web de Dados tem por base alguns padrões, como: o
mesmo mecanismo de identificação e acesso universal usado na Web de
documentos (as URIs e o HTTP); um modelo padrão para representação de dados,
o RDF e uma linguagem de consulta para acesso aos dados, a linguagem SPARQL.
A seguir esses padrões são apresentados.
URIs – Uniform Resource Identifiers
URI é uma cadeia de caracteres compacta usada para identificar ou denominar um
recurso na Internet, onde um recurso pode ser um documento html, uma figura ou
uma pessoa. O principal propósito desta identificação é permitir a interação com
representações do recurso através de uma rede, tipicamente a Web, usando
protocolos específicos. Uma URI pode ser classificado como um localizador URL
(Uniform Resource Locator) ou um nome URN (Uniform Resource Name), ou
ainda como ambos. O URN define a identidade de um item, enquanto que o URL
nos dá um método para encontrá-lo. Tecnicamente URL e URN funcionam como
IDs de recursos, no entanto, muitos conjuntos não podem ser categorizados como
somente um ou outro, por que todas as URIs podem ser tratados como nomes, e
alguns conjuntos integram aspectos de ambas ou de nenhuma das categorias.
No contexto Linked Data, URIs são usadas para identificar objetos e
conceitos, permitindo que eles sejam dereferenciados para obtenção de informações
a seu respeito. Assim, o dereferenciamento de uma URI resulta em uma descrição
RDF
do
recurso
identificado.
Por
exemplo,
a
URI
http://www.w3.org/People/Berners-Lee/card#i identifica o pesquisador Tim
Bernes-Lee.
HTTP – HyperText Transfer Protocol
HTTP é um protocolo de aplicação responsável pelo tratamento de pedidos e
respostas entre cliente e servidor na Web. Ele surgiu da necessidade de distribuir
informações pela Internet e, para que essa distribuição fosse possível, foi
81
necessário criar uma forma padronizada de comunicação entre os clientes e os
servidores da Web. Com isso, o protocolo HTTP passou a ser utilizado para a
comunicação entre computadores na Internet e a especificar como seriam realizadas
as transações entre clientes e servidores, através do uso de regras básicas.
O HTTP utiliza o modelo cliente-servidor, como a maioria dos protocolos
de rede, baseando-se no paradigma de requisição e resposta. Um programa
requisitante (cliente) estabelece uma conexão com um outro programa receptor
(servidor) e envia-lhe uma requisição, contendo a URI, a versão do protocolo, uma
mensagem contendo os modificadores da requisição, informações sobre o cliente e,
possivelmente, o conteúdo no corpo da mensagem. O servidor responde com uma
linha de status (status line) incluindo sua versão de protocolo e com os códigos de
erro informando se a operação foi bem sucedida ou não, seguido pelas informações
do servidor, informações da entidade e possível conteúdo no corpo da mensagem.
Após o envio da resposta pelo servidor, encerra-se a conexão estabelecida.
RDF – Resource Description Framework
A utilização de um modelo padrão para representação de dados, como o RDF, torna
possível a implementação de aplicações genéricas capazes de operar sobre o espaço
de dados global [Heath & Bizer 2011]. O modelo RDF é baseado no conceito de
grafo, é extensível e possue um alto nível de expressividade, facilitando, dessa
forma, a interligação entre dados de diferentes fontes.
Em RDF, um recurso pode estar relacionado com dados ou com outros
recursos através das sentenças, as quais são estruturadas no formato sujeito +
predicado + objeto, onde:
 Sujeito: Tem como valor o recurso sobre o qual se quer escrever uma sentença.
Todo recurso deve ser capaz de ser identificado unicamente.
 Predicado: Especifica um relacionamento entre um sujeito e um objeto. O
predicado é especificado por meio de propriedades, que são relações binárias
geralmente nomeadas por um verbo e permitem relacionar um recurso a dados ou
a outros recursos. Uma propriedade também é um recurso e, portanto, deve ter um
identificador único.
 Objeto: Denomina o recurso ou dado que se relaciona com o sujeito. O valor de
um objeto pode ser um recurso ou um literal, que pode ser um valor numérico ou
uma cadeia de caracteres.
A Figura 4.1 mostra alguns exemplos de triplas RDF.
Figura 4.1. Triplas RDF.
82
As triplas representadas na Figura 4.1 contêm informações sobre dois recursos.
A primeira tripla informa que o recurso “p91002043177” possui nome Berna Farias.
A segunda tripla descreve um segundo recurso “CK120”, cujo nome é “Banco de
Dados I”. A terceira tripla descreve um relacionamento entre os dois recursos criados
através do predicado “EnsinadoPor”. Cada tripla faz parte da Web de Dados e pode
ser usada como ponto de partida para explorar esse espaço de dados. Triplas de
diferentes fontes podem ser facilmente combinadas para formar um único grafo.
Além disso, é possível usar termos de diferentes vocabulários para representar os
dados. O modelo RDF ainda permite a representação de dados em diferentes níveis
de estruturação, sendo possível representar desde dados semiestruturados a dados
altamente estruturados.
SPARQL
Assim como os sistemas de bancos de dados relacionais fazem uso do SQL para
consultar registros nas suas bases de dados, SPARQL é a linguagem de consulta
padrão recomendada pelo W3C para recuperação de informações contidas em
grafos RDF. Apesar de existirem outras linguagens de consulta (SeRQL, RQL,
etc..) mais antigas, maduras e com maior poder de expressividade que o SPARQL,
estas ou foram projetadas para se trabalhar em um domínio específico ou são
interpretadas apenas por algumas poucas ferramentas, o que acaba resultando em
uma baixa interoperabilidade.
onde:
Semelhante ao SQL, o SPARQL possui uma estrutura Select-From-Where
• Select: Especifica uma projeção sobre os dados como a ordem e a quantidade de
atributos e/ou instâncias que serão retornados.
• From: Declara as fontes que serão consultadas. Esta cláusula é opcional.
Quando não especificada, assumimos que a busca será feita em um documento
RDF/RDFS particular.
• Where: Impões restrições na consulta. Os registros retornados pela consulta
deverão satisfazer as restrições impostas por esta cláusula.
O resultado de uma consulta SPARQL pode ser encarado como um subgrafo
resultante da execução da consulta sobre o grafo que representa o modelo.
Considere por exemplo o grafo apresentado na Figura 4.2 extraído de [Allemang &
Hendler 2008].
83
Figura 4.2. Representação das instâncias de um domínio
O grafo da Figura 4.2 representa a relação entre as instâncias de uma
ontologia cujo domínio é focado na descrição e formalização de escritores. O
subgrafo destacado em negrito pode ser encarado, por exemplo, como o resultado
de uma consulta que retorna o escritor que escreveu o livro King Lear e é casado
com AnneHathaway.
4.3. Princípios Linked Data
O termo Linked Data refere-se ao conjunto de melhores práticas para a publicação
de dados estruturados na Web. Essas práticas foram introduzidas por Tim BernersLee em [Lee et al 2006] e resumem-se em quatro princípios básicos:
1.Usar URIs como nome para recursos.
2.Usar URIs HTTP para que as pessoas possam encontrar esses nomes.
3.Quando alguém procura por uma URI, garantir que informações úteis
possam ser obtidas por meio dessa URI, as quais devem estar representadas no
formato RDF.
4.Incluir links para outras URIs de forma que outros recursos possam ser
descobertos.
O primeiro princípio defende o uso de referências URI para identificar, não
apenas documentos Web e conteúdos digitais, mas também objetos do mundo real e
conceitos abstratos.
84
O segundo princípio defende o uso de URIs HTTP para identificar os objetos
e os conceitos abstratos definidos pelo princípio 1, possibilitando essas URIs serem
dereferenciáveis sobre um protocolo HTTP. Neste contexto, dereferenciar é o
processo de recuperar uma representação de um recurso identificado por uma URI,
onde um recurso pode ter várias representações como documentos HTML, RDF,
XML entre outros.
A fim de permitir que uma ampla gama de aplicações diferentes possam
processar dados disponíveis na Web, é importante que exista um acordo sobre o
formato padrão para disponibilização dos dados. O terceiro princípio Linked Data
defende o uso de RDF como modelo para a publicação de dados estruturados na Web
[Klyne et al. 2004]. Com o RDF, é possível descrever significado sobre recursos,
habilitando agentes de software a explorar os dados de forma automática, muitas
vezes, agregando, interpretando ou mesclando dados.
O quarto princípio diz respeito ao uso de hiperlinks para conectar não apenas
os documentos da Web, mas qualquer tipo de recurso. Por exemplo, uma ligação
pode ser fixada entre uma pessoa e um lugar, ou entre um local e uma empresa. Em
contraste com a Web clássica onde os hiperlinks são em grande parte não tipados,
hiperlinks que conectam os recursos em um contexto de Linked Data são capazes de
descrever a relação entre eles. Hyperlinks no contexto de Linked Data são chamados
de links RDF, a fim de distingui-los dos hiperlinks existentes na Web convencional
[Heath & Bizer 2011].
O exemplo mais visível da adoção e aplicação dos princípios Linked Data
tem sido o projeto Linking Open Data1 fundado em janeiro de 2007 e apoiado pelo
W3C Semantic Web Education and Outreach Group2. O objetivo principal desse
projeto é identificar conjuntos de dados disponíveis sob licenças abertas e convertêlos para RDF de acordo com os princípios Linked Data.
Os participantes nas fases iniciais do projeto foram os pesquisadores e
desenvolvedores de laboratórios universitários e empresas de pequeno porte. Desde
então, o projeto tem crescido consideravelmente, conseguindo um envolvimento
significativo de grandes organizações como a BBC3. Este crescimento é possível
graças à natureza aberta do projeto, onde qualquer um pode participar, sendo
necessário apenas publicar um conjunto de dados de acordo com os princípios Linked
Data e interligá-lo aos conjuntos de dados já existentes. Na Figura 4.3 podem-se
observar os diversos conjuntos de dados publicados no contexto do projeto Linking
Open Data.
1
http://www.w3.org/wiki/SweoIG/TaskForces/CommunityProjects/LinkingOpenData
http://www.w3.org/2001/sw/sweo/
3
http://www.bbc.co.uk/
2
85
Figura 4.3. Visão geral de conjuntos de dados publicados e seus relacionamentos em Setembro de
2011.
No grafo da Figura 4.3, cada nó representa um conjunto de dados publicado
seguindo os princípios Linked Data, os quais estão interligados com outros
conjuntos de dados na nuvem. O tamanho de cada nó corresponde ao número de
triplas RDF do conjunto de dados. As setas indicam a existência de pelo menos 50
ligações entre dois conjuntos, podendo ser unidirecionais, indicando que um certo
conjunto contem triplas RDF de um outro conjunto, ou bidirecionais, indicando que
ambos os conjuntos contem triplas RDF um do outro.
O conteúdo da nuvem possui natureza diversa, incluindo dados sobre
localizações geográficas, empresas, livros, publicações científicas, filmes, música,
televisão e rádio, ensaios clínicos, comunidades online, dados estatísticos entre
outros [Heath & Bizer 2011].
4.4. Diretrizes para Publicação de dados em Linked Data
De acordo com [Heath & Bizer 2011], a adoção das melhores práticas de publicação
de dados ligados facilita a descoberta de informações relevantes para a integração de
dados entre diferentes fontes. A seguir são apresentados alguns passos para publicar
dados na Web de Dados, como definido em [Heath & Bizer 2011].
4.4.1. Criação de URIs adequadas
Como mencionado anteriormente, recursos são nomeados a partir de URIs. Dessa
forma, ao publicar dados Linked Data é preciso fazer um esforço para criar boas
URIs para identificação dos recursos. Para isso, devem ser feitas algumas
considerações, incluindo:
 Usar URIs HTTP para tudo, tornando-as passíveis de serem dereferenciadas.
 Evitar URIs com detalhes de implementação ou do ambiente em que estão
publicadas. Por exemplo, a URI http://www.lia.ufc.br:8080/~danusarbc
86
/index.php é um exemplo do que deve ser evitado, pois possui detalhes da porta
8080 usada em seu ambiente de publicação e do script implementado em PHP
necessário para sua execução.
 Manter as URIs estáveis e persistentes, pois a alteração das URIs pode levar à
quebra de links já estabelecidos, criando um problema para a localização de
recursos. Para evitar esse tipo de alteração, recomenda-se um planejamento das
URIs que serão usadas e também que o responsável pela publicação detenha a
propriedade do espaço de nomes
 Muitas vezes será preciso usar algum tipo de chave primária dentro das URIs,
para se certificar de que cada uma delas é única. Se possível, usar uma chave que
é significativa dentro do domínio para o qual está sendo criada a URI. Por
exemplo, quando se trata de livros, pode-se usar o ISBN como identificador
único.
Essas são apenas algumas características desejáveis para serem consideradas
quando se for criar uma URI. Maiores detalhes podem ser encontrados no tutorial
Cool URIs for the Semantic Web4 disponibilizado pela W3C.
4.4.2. Usar URIs dereferenciáveis
Qualquer URI HTTP deve ser capaz de ser dereferenciada, o que significa que
clientes HTTP podem procurar por uma URI usando um protocolo HTTP e recuperar
uma descrição do recurso que é identificado pela URI.
A recuperação da representação mais adequada para o usuário é feita por
meio da negociação de conteúdo. Assim, clientes HTTP enviam, por meio dos
cabeçalhos HTTP (Get, Head, Post, Put, Delete, Trace, Options, Connection), o
pedido para indicar qual tipo de conteúdo deseja obter. Após isso, ao receber uma
requisição, o servidor analisa o cabeçalho e seleciona a resposta adequada. Há duas
estratégias para fazer URIs serem dereferenciáveis: 303 URI e Hash URI.
303 URI: 303 é um código de status de redirecionamento no qual o servidor pode dar
a localização de um documento que contém informações sobre um recurso. Por
exemplo, a Figura 4.4 mostra como ocorre o dereferenciamento quando um usuário
deseja obter informações sobre a cidade de Berlin da fonte DBpedia5. Primeiramente,
em 1, é especificado que o conteúdo desejado é no formato RDF/XML através do
comando Accept: text/html;q=0.5, application/rdf+xml. Após isso, em 2, o servidor
enviará para o cliente uma URI http://dbpedia.org/data/Berlin, mostrando a
localização exata do conteúdo requerido e o código 303 See Other, indicando que a
requisição será redirecionada para essa URI. Com essa URI em mãos, em 3, o cliente
reenvia sua solicitação e, por fim, em 4, recebe do servidor um arquivo RFD com o
conteúdo conforme solicitado.
4
5
http://www.w3.org/TR/cooluris/
http://dbpedia.org/
87
Figura 4.4. Dereferenciamento de URI utilizando a estratégia 303 URI.
Hash URI: Nessa estratégia, a URI contém um fragmento, uma parte especial que é
separada do resto da URI pelo símbolo #. Quando um cliente deseja recuperar uma
hash URI, ele remove tudo que vem após o símbolo # e envia o restante da URI para
o servidor. Como resposta, o cliente recebe um documento completo com o conteúdo
solicitado. Para um melhor entendimento, a Figura 4.5 mostra como ocorre o
dereferenciamento utilizando Hash URI para o seguinte exemplo: suponha um
arquivo que contém um vocabulário definido para uma empresa fictícia chamada
Small and Medium-sized Enterprises representado pela seguinte URI:
http://biglynx.co.uk/vocab/sme. As seguintes URIs foram criados para identificar
termos distintos que podem ser encontrados no documentos previamente criado:
http://biglynx.co.uk/vocab/sme#Small
MediumEnterprise
e
http://biglynx.co.uk/vocab/sme#Team. Para dereferenciar qualquer uma dessas duas
URIs, o cliente removerá o fragmento especial (#Team por exemplo) e então enviará
sua requisição para o servidor, especificando que o conteúdo desejado é no formato
RDF/XML através do comando Accept: application/rdf+xml conforme visto em 1.
Em seguida, o servidor retornará como resposta, em 2, um documento contendo todo
o conteúdo expresso em http://biglynx.co.uk/vocab/sme.
88
Figura 4.5. Dereferenciamento de URI utilizando a estratégia Hash URI.
4.4.3. Criação de links RDF
De modo a permitir a navegação entre as fontes de dados, devem ser criados links
para outras fontes, seja de forma manual ou automatizada. Links no contexto de
Linked Data fazem referência aos de links RDF. Links RDF podem ser classificados
em dois tipos: links RDF internos e externos. O link RDF interno conecta recursos
dentro de uma única fonte de dados Linked Data. Links externos conectam recursos
os quais são provenientes de diferentes fontes de dados Linked Data. No caso de
links externos, as URIs referentes ao sujeito e predicado do link pertencem a
diferentes namespaces (os quais são URIs que referenciam o esquema do qual o
elemento faz parte). Links externos são cruciais para a Web dos Dados visto que eles
permitem juntar as fontes de dados dispersas em um espaço global de dados [Heath
& Bizer 2011].
A Figura 4.6 apresenta dois exemplos de links RDF. O primeiro exemplo
interliga o perfil FOAF6 do pesquisador Tim Berners-Lee localizado em um arquivo
RDF ao recurso que o identifica na fonte de dados do DBLP7. No segundo exemplo,
o recurso que identifica Tim Berners-Lee na fonte DBpedia8 também é ligado ao
recurso
na
fonte
DBLP
que
o
identifica.
A
propriedade
http://www.w3.org/2002/07/owl#sameAs define que os recursos interligados
representam a mesma entidade do mundo real.
Sujeito: http://www.w3.org/People/Berners-Lee/card#i
6
http://www.foaf-project.org/
http://www.informatik.uni-trier.de/~ley/db/
8
http://dbpedia.org/About
7
89
Predicado: http://www.w3.org/2002/07/owl\#sameAs
Objeto: http://www4.wiwiss.fu-berlin.de/dblp/resource/person/100007
Sujeito: http://dbpedia.org/resource/Tim\_Berners-Lee
Predicado: http://www.w3.org/2002/07/owl\#sameAs
Objeto: http://www4.wiwiss.fu-berlin.de/dblp/resource/person/100007
Figura 4.6. Exemplos de Links RDF.
Ao se criar links RDF é preciso estabelecer relações entre os termos dos
vocabulários entre as fontes que estão sendo interligadas. Embora não haja restrições
para seleção de vocabulários, é considerada uma boa prática o reuso de termos de
vocabulários RDF amplamente usados para facilitar o processamento de dados
ligados pelas aplicações clientes. Novos termos só devem ser definidos se não forem
encontrados em vocabulários já existentes. Alguns vocabulários bastante conhecidos
são: Friend-of-a-Friend (FOAF), Semantically-Interlinked Online Communities9
(SIOC), Simple Knowledge Organization System10 (SKOS), Description of a
Project11 (DOAP), Creative Commons12 (CC) e Dublin Core13 (DC). Propriedades
como:
owl:equivalentClass,
owl:equivalentProperty,
rdfs:subClassOf,
rdfs:subPropertyOf podem ser usadas para estabelecer equivalências entre os termos
dos vocabulários citados. Maiores detalhes sobre as linguagens OWL e RDFS podem
ser encontrados em [Filho & Lóscio 2009].
4.4.4. Explicitar formas de acesso adicional aos dados
Para acessar os dados das fontes Linked Data é preciso realizar consultas SPARQL
sobre as fontes. Para enviar consultas e recuperar resultados através da linguagem
SPARQL é usado o protocolo SPARQL14. Fontes Linked Data tipicamente fornecem
um SPARQL endpoint que é um serviço Web com suporte ao protocolo SPARQL.
Esse serviço possui uma URI específica para receber requisições HTTP com
consultas SPARQL e retornar os resultados dessas consultas em diferentes formatos
como XML, JSON15, texto, RDF/XML, NTriples16, Turtle17 ou N318 e HTML
[Magalhães et al 2011]. O framework Jena19 disponibiliza duas implementações de
SPARQL endpoints: o Joseki20 e o Fuseki21. Ambos suportam o protocolo e a
linguagem SPARQL, permitem a realização de consultas sobre arquivos RDF e RDF
9
http://sioc-project.org/
http://www.w3.org/2009/08/skos-reference/skos.html
11
http://trac.usefulinc.com/doap
12
http://creativecommons.org/
13
http://dublincore.org/
14
http://www.w3.org/TR/rdf-sparql-query/
15
http://www.json.org/
16
http://www.w3.org/2001/sw/RDFCore/ntriples/
17
http://www.w3.org/TR/turtle/
18
http://www.w3.org/TeamSubmission/n3/
19
http://incubator.apache.org/jena/
20
http://www.joseki.org/
21
http://openjena.org/wiki/Fuseki
10
90
Triple Stores, e implementam SPARQL Update22 (linguagem para atualizar RDF
store). A diferença principal entre eles é que o Fuseki é mais simples de configurar e
usar, além de já possuir a RDF Store Jena TDB23 embutida. No entanto o Fuseki é
um projeto mais recente, iniciado em 2011, que ainda possui limitações quanto ao
gerenciamento de múltiplas fontes de dados e também quanto ao uso de mecanismos
de segurança próprios [Magalhães et al 2011].
4.4.5.Padrões para Publicar Dados Linked Data
Para a publicação de dados RDF podem ser usadas ferramentas específicas de
conversão de planilhas, arquivos CSV, arquivos XML, dados relacionais e outros
documentos para o formato RDF como, por exemplo, a ferramenta ConvertToRDF24.
Após a geração do arquivo em formato RDF, os dados podem ser carregados em um
banco de dados que armazena as triplas RDF, chamado de RDF Store. A publicação
de dados de uma RDF Store, seguindo os princípios Linked Data, tipicamente
envolve a disponibilização de uma interface para acesso ao dados Linked Data e de
um SPARQL endpoint para acesso aos dados. Uma vantagem de se converter dados
para o formato RDF é a melhoria de desempenho que pode ser obtida ao usar formas
de armazenamento especificamente otimizadas para realizar a persistência de triplas
RDF. No entanto, o armazenamento das triplas requer espaço extra em relação aos
dados originais. Além disso, a conversão demanda um certo tempo para ser realizada
e os dados em RDF podem ficar desatualizados em relação aos dados originais.
Um outra forma de acessar dados que não estão no modelo RDF consiste em
fornecer uma visão RDF. Isso é feito através de um RDF Wrapper. Nesse caso, a
conversão é realizada por um RDF Wrapper por meio de mapeamentos estabelecidos
entre o modelo nativo e o modelo RDF, devendo haver um wrapper específico para
cada tipo de modelo. Um RDF Wrapper também pode prover uma visão RDF para
dados que precisam ser acessados através de uma Web API. Criar uma visão RDF
tende a ter um desempenho inferior à conversão de dados para RDF devido às
traduções dinâmicas entre os modelos que deve ser realizada a cada uso da visão
RDF. No entanto, o uso de RDF Wrappers traz algumas vantagens, pois como o
acesso ocorre sobre os dados originais, a visão RDF não requer espaço de
armazenamento extra e não corre o risco de apresentar dados desatualizados.
Um exemplo comum de utilização de visões RDF é a publicação de dados
armazenados em banco de dados relacionais. O RDB-to-RDF25 Wrappers é uma
solução que cria visões RDF a partir de mapeamentos entre as estruturas relacionais e
os grafos RDF. A plataforma D2RQ26 é um exemplo de RDB-to-RDF Wrappers, que
fornece toda a infraestrutura necessária para acessar bancos de dados relacionais
como grafos RDF virtuais. Esta plataforma possui os seguintes componentes:
 Linguagem de mapeamento D2RQ é uma linguagem declarativa para descrever
as correspondências entre o modelo relacional e o modelo RDF. Os mapeamentos
escritos em D2RQ são documentos RDF.
22
http://www.w3.org/Submission/SPARQL-Update/
http://openjena.org/TDB/
24
http://www.w3.org/wiki/ConverterToRdf
25
http://www.w3.org/TR/r2rml/
26
http://www4.wiwiss.fu-berlin.de/bizer/d2rq/spec/
23
91
 Mecanismo D2RQ é um plug-in para os frameworks Jena e Sesame que usa os
mapeamentos escritos na linguagem D2RQ para converter chamadas às APIs
desses frameworks em consultas SQL ao banco de dados para obtenção dos
resultados.
 Servidor D2R27 é um servidor HTTP que usa o mecanismo D2RQ para prover
uma interface Linked Data e um SPARQL endpoint sobre o banco de dados
relacional [Bizer & Cyganiak 2006].
Além do D2R, duas outras ferramentas destacam-se como RDB-to-RDF
Wrappers: o Virtuoso RDF Views [Erling & Mikhailov 2006] e o Triplify [Auer et al.
2009]. Este último é um plugin para aplicações Web que permite mapear os
resultados de consultas SQL em RDF e JSON. Depois disso, os dados podem ser
compartilhados e acessados na Web de dados.
Após gerar os dados no modelo RDF, é necessário verificar se o resultado
está de acordo com os princípios Linked Data. Essa verificação pode ser feita através
de ferramentas de validação como, por exemplo, Sindice Web Data Inspector28,
Eyeball29 e W3C Validation Service30.
A próxima seção apresentará uma série de aplicações Web que vem sendo
desenvolvidas para consumir os dados publicados nos padrões Linked Data.
4.5. Consumo de dados ligados
Nos últimos três anos, um número significativo de dados vem sendo disponibilizado
de acordo com os princípios Linked Data. Como resultado, uma série de aplicações
Web estão sendo desenvolvidas para explorar a Web de Dados. Segundo [Bizer et al
2009], essas aplicações podem ser classificadas em três categorias: browsers,
motores de buscas e aplicações para domínios específicos. Essa seção examinará
cada uma dessas categorias.
4.5.1. Browsers Linked Data
Assim como os tradicionais browsers da Web clássica permitem aos usuários
navegarem por páginas HTML, os browsers Linked Data permitem aos usuários
navegar por fontes de dados seguindo os links expressos nas triplas RDF. Por meio
destes browsers é possível percorrer os links RDF, explorando e descobrindo novas
informações na Web. A seguir, serão apresentados alguns exemplos de browsers
usados para acessar dados ligados.
Tabulator31 permite ao usuário percorrer a Web de Dados e expor parte dos
dados de uma forma controlada, onde o usuário pode dividir a informação por
tópicos. Os resultados das consultas podem ser analisados através de vários métodos,
que vão desde a apresentação de dados de maneira convencional até a apresentação
por meio de mapas. A utilização do modo de exploração inicia a partir da submissão
de uma URI. Depois disso, o Tabulator obtém informações sobre o recurso e as
27
http://www4.wiwiss.fu-berlin.de/bizer/d2r-server/
http://inspector.sindice.com/
29
http://jena.sourceforge.net/Eyeball/
30
http://www.w3.org/RDF/Validator/
31
http://www.w3.org/2005/ajar/tab
28
92
exibe como um grafo RDF em uma visão de árvore. A expansão de um nó permite a
obtenção de mais informações sobre ele. Para passar ao modo de análise, o usuário
pode selecionar predicados para definir um padrão e requisitar que o Tabulator
encontre todos os exemplos daquele padrão. Os resultados podem ser exibidos
através das visões de tabela, mapas, calendários ou linhas de tempo. Pode-se iniciar
uma nova exploração pela seleção de um detalhe de uma das visões. O Tabulator
pode ser usado como um complemento do navegador Firefox ou como uma aplicação
Web que atualmente é compatível apenas com o Firefox [Lee et al. 2006].
Marbles32 é um aplicativo do lado do servidor que formata o conteúdo da
Web Semântica para clientes XHTML. Pontos coloridos são usados para
correlacionar a origem dos dados apresentados com as fontes de dados de onde foram
encontrados. Os dados são recuperados de múltiplas fontes e integrados em um único
grafo que é mantido através das sessões do usuário. Além de dereferenciar a URI,
Marbles consulta os mecanismos de busca Sindice e Falcons em busca de fontes que
contenham informações sobre o recurso referenciado pela URI dada como entrada
para a busca. Além disso, os predicados owl:sameAs e rdfs:seeAlso são seguidos para
obtenção de informações adicionais sobre o recurso. A Figura 4.7 apresenta
como o Marbles disponibiliza os dados para o usuário após uma consulta. Os pontos
coloridos indicam as fontes de dados que forneceram os dados para o usuário. Dessa
forma, o usuário pode clicar sobre as fontes e encontrar mais informações para a sua
busca.
Figura 4.7. Visualização de Informações sobre recursos do Browser Marbles.
32
http://marbles.sourceforge.net/
93
Disco Hiperdata Browser33 é uma aplicação Web usada como navegador
simples para visualizar informações sobre um recurso por meio de uma página
HTML. Para iniciar a navegação, o usuário digita a URI do recurso em uma caixa de
texto e pressiona o botão “Go”. A partir daí, o browser recupera as informações
sobre o recurso e as exibe em uma tabela contendo propriedades, valores e as fontes
das quais os dados foram recuperados. Os links exibidos permitem a navegação entre
os recursos, de modo que ao selecionar um novo recurso, o navegador
dinamicamente recupera informações sobre ele através do dereferenciamento de sua
URI. À medida que a navegação é feita, Disco armazena os grafos RDF recuperados
em um cache de sessão. Ao clicar sobre o link “Display all RDF graphs”, uma nova
janela é aberta contendo a lista dos grafos RDF recuperados e das URIs que não
foram dereferenciadas com sucesso. Disco pode ser usado de forma online ou
executado localmente.
Além das aplicações descritas acima, destacam-se: Dipper34, Piggy Bank35,
URI Burner36, LinkSailor37 e Graphite RDF Browser38 como browsers simples e
rápidos para obter detalhes sobre uma determinada URI após dereferenciá-la.
4.5.2. Motores de Busca Linked Data
Um grande número de motores de busca tem sido desenvolvido para rastrear dados
no padrão Linked Dados. Esses mecanismos de busca permitem localizar recursos de
diferentes fontes por meio de palavras-chave. A consulta pode ser realizada pelo
usuário através de uma interface Web ou através de serviços Web oferecidos pelos
mecanismos de busca. A seguir são apresentados alguns dos motores de busca mais
utilizados.
Falcons permite tanto uma busca por palavras-chave, como oferece ao
usuário a opção de buscar objetos, conceitos e documentos, possibilitando uma
apresentação dos resultados um pouco diferente dos demais motores de busca. A
busca por objeto é adequado para a busca por pessoas, lugares e outros itens
considerados concretos, enquanto que a busca por conceito é orientada para a
localização de classes e propriedades em ontologias publicadas na Web. O recurso de
pesquisa por documento segue uma abordagem mais tradicional, onde os resultados
apontam para documentos RDF que contêm os termos de pesquisa especificados
[Cheg & Qu 2011].
Sindice39 coleta dados estruturados na Web (RDF, RDFa e microformatos) e
os indexa por URIs, propriedades funcionais inversas (IFPs) e palavras-chave,
oferecendo uma interface Web para que os usuários possam fazer buscas a partir dos
itens indexados. Sindice também fornece um SPARQL endpoint que permite a
realização de consultas sobre todos os seus dados e uma API que permite a utilização
33
http://www4.wiwiss.fu-berlin.de/rdf_browser/
http://api.talis.com/stores/iand-dev1/items/dipper.html
35
http://simile.mit.edu
36
http://linkeddata.uriburner.com
37
http://linksailor.com/
38
http://graphite.ecs.soton.ac.uk/browser/
39
http://sindice.com/
34
94
de seus serviços por outras aplicações [Oren et al 2008]. Na Figura 4.8 pode-se
observar como o motor de busca Sindice apresenta o resultado de uma consulta ao
usuário.
Figura 4.8. Resultado mostrado pelo Sindice sobre a pesquisadora Bernadette Farias Lóscio.
Sig.ma40 busca dados estruturados a partir de uma palavra-chave e os exibe
em uma única página, integrando os dados de múltiplas fontes. A visão criada pelo
Sig.ma baseia-se em resultados fornecidos pelo Sindice. O usuário pode aprovar,
rejeitar ou acrescentar fontes para estabelecer uma visão dos dados relevantes. Ao
selecionar uma entidade da lista de resultados, uma nova visão é apresentada ao
usuário. Um link permanente pode ser criado para futuros acessos ou
compartilhamento dessa visão. Os filtros aplicados nas fontes pelos usuários ajudam
a classificar melhor a relevância das fontes e aperfeiçoar a qualidade dos resultados
futuros. Além da interface Web do usuário, Sig.ma ainda fornece uma API destinada
aos desenvolvedores de aplicações. A Figura 4. 9 ilustra o resultado de uma consulta
sobre a pesquisadora Damires Yluska envolvendo três fontes nas quais ela é
referenciada.
40
http://sig.ma/
95
Figura 4.9. Visão criada pelo Sig.ma sobre a pesquisadora Damires Yluska.
Watson41 e Swoogle42 são mecanismos de busca mais voltados para a
descoberta de informações sobre ontologias. Podem ser usados, por exemplo, para
obter ontologias que possuem determinados conceitos e descobrir relacionamentos
entre termos. Yahoo e Google também deram início ao uso de Linked Data. Yahoo
provê acesso aos dados através da BOSS API43, enquanto o Google usa os dados para
a Social Graph API44.
4.5.3. Aplicações para Domínios Específicos
Enquanto os browsers Linked Data e motores de busca descritos anteriormente
fornecem funcionalidades muito genéricas, uma série de serviços, chamadas de
Linked Data Mashups, foram desenvolvidos com o objetivo de prover
funcionalidades mais específicas e de acordo com determinados domínios de dados.
A seguir descreveremos algumas dessas aplicações [Lee et al 2006].
Revyu45 é uma aplicação Web para crítica e classificação de qualquer item
passível de avaliação. Revyu também disponibiliza uma API e um SPARQL endpoint
para serem usados pelos desenvolvedores de aplicações.
DBpedia Mobile46 é uma aplicação cliente para dispositivos móveis
consistindo de uma visão com um mapa e do navegador Linked Data Marbles.
Baseado na localização geográfica de um dispositivo móvel, a aplicação exibe um
mapa indicando localizações próximas a partir de dados extraídos das fontes
DBpedia, Revyu e Flickr. O acesso ao Flickr é realizado através de um Wrapper. O
usuário pode explorar informações sobre essas localizações e navegar em conjuntos
de dados interligados. Também é possível a publicação de informações como Linked
Data, de modo que possam ser usadas por outras aplicações [Becker & Bizer 2008].
Talis Aspire47 é uma aplicação Web voltada para que alunos e professores e
possam encontrar os principais recursos educacionais em universidades do Reino
41
http://watson.kmi.open.ac.uk/WatsonWUI/
http://swoogle.umbc.edu/
43
http://developer.yahoo.com/search/boss/boss_api_guide/
44
http://code.google.com/intl/pt-BR/apis/socialgraph/
45
http://revyu.com/
46
http://beckr.org/DBpediaMobile/
47
http://www.talisaspire.com/
42
96
Unido. O serviço é gratuito e provê ferramentas para criar e editar listas de leitura,
além da produção e publicação de materiais educativos. Quando o usuário publica
conteúdo, a aplicação cria triplas RDF em uma RDF store. Itens publicados são
interligados de forma transparente a itens correspondentes de outras instituições.
BBC Programmes48 e BBC Music49 são projetos desenvolvidos pela BBC
Audio and Music Interactive. A aplicação Web BBC Programmes disponibiliza
informações detalhadas sobre tipos, séries e episódios de todos os programas de TV e
rádio transmitidos pela BBC. BBC Music fornece informações sobre artistas,
vinculando-os aos programas da BBC. Assim é possível escolher um artista e obter
todos os episódios de programas relacionados a ele. As aplicações mencionadas
usam Linked Data como tecnologia de integração de dados, inclusive fazendo uso de
vocabulários amplamente conhecidos como DBpedia e MusicBrainz50.
LinkedDataBr é um projeto brasileiro que visa construir uma infra-estrutura
de suporte à criação de repositórios de dados governamentais públicos utilizando os
padrões de Linked Data. A ideia consiste em utilizar e ligar dados governamentais
disponíveis na Web, gerados a partir das iniciativas de e-gov e open-government, de
forma a possibilitar a publicação padronizada e o acesso por parte dos cidadãos e
organizações [Campos 2010].
4.6. Considerações Finais
O imenso emaranhado de documentos acessíveis na Web é composto de dados e
informações de praticamente todas as áreas do conhecimento humano. Contudo,
ainda é árdua a tarefa de prover meios eficientes que permitam aproveitar todo esse
conteúdo, que pode ser composto tanto por dados estruturados, como os dados
provenientes de bancos de dados relacionais, quanto por dados não estruturados,
como textos e dados multimídia. No cenário da Web atual, o grande volume de
dados e a falta de metadados dificultam o acesso à informação útil, específica e
relevante.
Neste contexto, espera-se que o uso dos princípios do Linked Data possibilite
a transformação de uma Web na qual os recursos são documentos HTML para uma
Web de Dados, onde os dados estarão interligados através de metadados. O tema
Linked Data traz novos desafios para o desenvolvimento de aplicações Web de uma
maneira geral, bem como para o gerenciamento da grande nuvem de dados que vem
se formando como resultado da crescente adoção dos princípios do Linked Data.
Tendo em vista a relevância deste assunto para a comunidade de Computação e o
grande potencial de pesquisa desta área, Linked Data tem sido o foco de diversas
conferências internacionais, bem como o foco de estudo de diversos grupos de
pesquisa. Dessa forma, torna-se de fundamental importância que este tema seja
amplamente abordado e discutido por pesquisadores, alunos e profissionais da área
de Computação.
48
http://www.bbc.co.uk/programmes
http://www.bbc.co.uk/music
50
http://musicbrainz.org/
49
97
Referências
[Allemang & Hendler 2008] Allemang, D., Hendler, D. (2008) Semantic Web for the
Working Ontologist, 1st edition. Morgan Kaufmann publ., Amsterdam,
Netherlands.
[Auer et al. 2009] Auer, S., Dietzold, S., Lehmann, J., Hellmann, S., and Aumueller,
D. (2009) Triplify: Light-weight linked data publication from relational
databases. In Quemada, J., León, G., Maarek, Y. S., and Nejdl, W., editors,
Proceedings of the 18th International Conference on World Wide Web, WWW
2009, Madrid, Spain, April 20-24, 2009, pages 621–630. ACM.
[Becker & Bizer 2008] Becker, C., Bizer, C. (2008) DBpedia Mobile: A LocationEnabled Linked Data Browser. In Linked Data on the Web (LDOW2008).
[Bizer & Cyganiak 2006] Bizer, C., Cyganiak, R. (2006) D2R Server – Publishing
Relational Databases on the Semantic Web. In 5th International Semantic Web
Conference.
[Bizer et al 2009] Bizer C., Heath T., Berners-Lee T. (2009) Linked data - the story
so far. Int. J. Semantic Web Inf. Syst., 5(3):1–22, 2009.
[Campos 2010] Campos M. L. (2010) GT-LinkedDataBR – Exposição,
compartilhamento e conexão de recursos de dados abertos na Web (Linked Open
Data). Disponível em http://www.rnp.br/pd/gts2010-2011/gt_linkeddatabr.html
[Cheg & Qu 2011] Cheng, G., Qu, Y. (2011) Searching Linked Objects with
Falcons: Approach, Implementation and Evaluation. International Journal on
Semantic Web and Information Systems, Special Issue on Linked Data.
[Costa & Yamate 2009] Costa A., Yamate F. (2009) Semantic Lattes: uma
ferramenta de consulta baseada em ontologias. Trabalho de Grduação em
Engenharia de Computação - Escola Politécnica. IME/USP.
[Erling & Mikhailov 2006] Erling, O., Mikhailov, I. (2006) Mapping Relational
Data to RDF in Virtuoso. http://virtuoso.openlinksw.com/dataspace/dav/wiki/
Main/VOSSQLRDF.
[Filho & Lóscio 2009] Filho, F. W. B. H , Lóscio B. F. (2009) Web Semântica:
Conceitos e Tecnologias. In Anais do ERCEMAPI (Escola Regional de
Computação Ceará – Maranhão – Piauí).
[Freitas 2003] Freitas, F. L. G. (2003) Ontologias e a Web Semântica. XXIII
Congresso da Sociedade Brasileira de Computação. JAI. Campinas, São Paulo,
Junho de 2003.
[Gruber 1995] Gruber T. (1995) Toward principles for the design of ontologies used
for knowledge sharing. 1995. International Journal Human-Computer Studies Vol.
43, Issues 5-6, November 1995, p.907-928.
[Heath & Bizer 2011] Heath, T., Bizer, C. (2011) Linked Data: Evolving the Web
into a Global Data Space (1st edition). Synthesis Lectures on the Semantic Web:
Theory and Technology, 1:1, 1-136. Morgan & Claypool, 2011.
98
[Klyne et al 2004] Klyne, G., Carroll, JJ., McBride., B. (2004) Resource description
framework (RDF): Concepts and abstract syntax. Disponível em:
http://www.w3.org/TR/rdf-concepts/
[Lee et al 2006] Lee, B. T., Chen, Y., Chilton, L., Connolly, D., Dhanaraj, R., Hollenbach, J., Lerer, A., and Sheets, D. (2006) Tabulator: Exploring and Analyzing
Linked Data on the Semantic Web. In In Procedings of the 3rd International
Semantic Web User Interaction Workshop (SWUI06, page 06.
[Lee et al 2001] Lee, B. T., Hendler J., Lassilia O. (2001) The semantic web.
Scientific
American,
284(5):34–44,
Mai
2001.
http://dx.doi.org/10.1038/scientificamerican0501-34DOI:
10.1038/scientificamerican0501-34
[Magalhães et al 2011] Magalhães, R. P., Macedo, J. A. F., Vidal, V. M. P. (2011)
Linked Data: Construindo um Espaço de Dados Global na Web. In Anais do
XXIV Simpósio Brasileiro de Banco de Dados. Outubro de 2011.
[Oren et al 2008] Oren, E., Delbru, R., Catasta, M., Cyganiak, R., Stenzhorn, H., and
Tumma-rello, G. (2008) Sindice.com: a document-oriented lookup index for open
linked data. Int. J.Metadata Semant. Ontologies, 3:37–52.
[Souza 2009] Souza D. (2009) Using Semantics to Enhance Query Reformulation in
Dynamic Distributed Environments. PhD Thesis, Federal University of
Pernambuco (UFPE), Recife, PE, Brazil.
99
Capítulo
5
Desenvolvimento de Aplicações para Plataforma
Google Android
Fábio de Jesus Lima Gomes, Manoel Taenan Ferreira de Souza, Rafael
Madureira Lins de Araújo
Abstract
Com a evolução da tecnologia móvel, os dispositivos móveis tornaram-se uma
importante fonte de transmissão e recepção de informações, gerando a necessidade de
sistemas operacionais mais robustos e uma considerável demanda para o
desenvolvimento de serviços e aplicações. A plataforma Google Android surgiu para
preencher esta lacuna. Dessa forma, este mini-curso pretende disseminar conceitos
envolvidos no desenvolvimento de serviços e aplicações para a plataforma Google
Android. Também será abordado como aplicações para dispositivos móveis podem
consumir serviços web através da arquitetura REST.
Resumo
With the evolution of mobile technology, mobile devices have become an important
source of transmission and reception of information, creating the need for more robust
operating systems and a considerable demand for the development of services and
applications. The Google Android platform was created in order to fill this gap. Thus,
this mini-course aims disseminate concepts about developing services and applications
for the Google Android platform. Also we will describe how mobile applications can
consume web services via REST architecture.
5.1. Introdução
O Google Android OS, também chamado apenas de Android, é um sistema operacional
de código aberto para dispositivos móveis e utiliza uma versão modificada do Sistema
Operacional Linux. Permite a desenvolvedores criarem aplicações Java que controlam o
dispositivo através de bibliotecas desenvolvidas pela Google. O Android também provê
uma infra-estrutura robusta de execução de aplicações Java. Apesar de ser recente (seu
100
lançamento foi em 2008), o Android foi adotado rapidamente por diversos fabricantes
de dispositivos móveis e atualmente é a plataforma que mais cresce no mundo.
Atualmente, a plataforma Google Android é mantida pela OHA (Open Handset
Alliance), um grupo formado por mais de 40 empresas que se uniram para inovar e
acelerar o desenvolvimento de aplicações e serviços para dispositivos móveis, trazendo
aos consumidores uma experiência mais rica em termos de recursos e menos onerosa
financeiramente para o mercado. Pode-se dizer que a plataforma Google Android é a
primeira plataforma completa, aberta e livre para dispositivos móveis. O Android SDK
é o kit de desenvolvimento que disponibiliza as ferramentas e APIs necessárias para
desenvolver aplicações para a plataforma Google Android, utilizando a linguagem Java.
Este mini-curso visa abordar conceitos envolvidos sobre desenvolvimento de
aplicações para a plataforma Google Android, apresentando os principais aspectos do
desenvolvimento de aplicações para dispositivos móveis, com enfoque para o
desenvolvimento de aplicações que consomem serviços web utilizando a linguagem
Java. Pretende-se capacitar os participantes no desenvolvimento de aplicações Java para
plataforma Google Android com base no Android SDK e demonstrar a arquitetura
REST (Representational State Transfer) de desenvolvimento de aplicações web. O
curso procura explorar as funcionalidades dessas tecnologias através do
desenvolvimento passo a passo de aplicações-exemplos.
5.2. Arquitetura do Google Android
Android é uma pilha de software para dispositivos móveis que inclui sistema
operacional, middleware e aplicações-chave. Esta pilha possui 4 níveis (Google, 2011):
Figura 5.1 Arquitetura da Plataforma Google Android (Google, 2011)
101
1.
LINUX KERNEL: a base da pilha é o kernel. O Google usou a versão 2.6 do Linux
para construir o kernel do Android, que inclui serviços essenciais do sistema, tais
como, gerenciamento de memória, gerenciamento de processos, gerenciamento de
energia, configurações de segurança, configurações de rede e drivers. O kernel
também atua como uma camada de abstração entre o hardware do dispositivo e os
outros níveis da pilha de software.
2.
RUNTIME ANDROID e LIBRARIES: acima do kernel estão as bibliotecas do
Android e o android runtime. Android runtime consiste de um conjunto de
bibliotecas que fornece a maioria das funcionalidades disponíveis nas principais
bibliotecas da linguagem de programação Java e de uma Máquina Virtual Dalvik
(DVM). Uma aplicação Android roda em seu próprio processo, com a sua própria
instância da máquina virtual Dalvik. Dessa forma, nenhuma aplicação é dependente
de outra; se uma aplicação pára, ela não afeta quaisquer outras aplicações
executando no dispositivo e isso simplifica o gerenciamento de memória. Dalvik
foi escrito de modo que um dispositivo possa executar várias VMs eficientemente.
Android possui um conjunto de bibliotecas C/C ++ usado por diversos
componentes da plataforma. As principais bibliotecas são listadas abaixo:
 System C library – uma implementação da biblioteca padrão C (libc), derivada
do sistema operacional BSD, alterada para dispositivos embarcados baseados no
Linux;
 Media Libraries – baseada no OpenCORE da PacketVideo; estas bibliotecas
suportam reprodução e gravação de muitos formatos populares de áudio, vídeo e
imagem, tais como, MPEG4, H.264, MP3, AAC, AMR, JPG, e PNG.
 Surface Manager – gerencia acesso ao sub-sistema de exibição e compõe as
camadas gráficas 2D e 3D para as aplicações.
 LibWebCore – um moderno engine para um navegador web que alimenta o
navegador do Android.
 SGL – engine de gráficos 2D.
 3D libraries – uma implementação baseada nas APIs OpenGL ES 1.0; estas
bibliotecas usam aceleração de hardware 3D (quando disponível) ou o software
embutido no sistema.
 FreeType – renderizador de bitmap e fontes vetorizadas.
 SQLite – engine leve e poderoso de banco de dados relacional para as aplicações.
3.
APPLICATION FRAMEWORK: O próximo nível é o framework de aplicação que
consiste nos programas que gerenciam as funções básicas do telefone, tais como,
alocação de recursos, aplicações de telefone, mudança entre processos ou
programas e informações sobre a localização física do aparelho. Os
desenvolvedores de aplicações têm acesso total ao framework de aplicação do
Android. Isso possibilita tirar vantagem das capacidades de processamento e do
suporte de recursos do Android.
102
4.
APPLICATIONS: No topo da pilha estão as aplicações em si. Aqui se encontram as
funções básicas do dispositivo, como fazer chamadas telefônicas, acessar o
navegador web ou acessar sua lista de contatos. Esta é a camada do usuário comum,
que utiliza a interface de usuário. Apenas os programadores do Google, os
desenvolvedores de aplicação e os fabricantes de hardware acessam as camadas
inferiores da pilha. O Android contém um conjunto de aplicativos, implementados
em Java, como um cliente de e-mail, programa para SMS (Short Message Service),
calendário, mapas, navegador e gerenciador de contatos.
5.3. Componentes de uma aplicação Android
As aplicações Android podem ser divididas em quatro tipos de componentes básicos
que são definidos pela própria arquitetura (ABLESON,2007), são eles:
5.3.1. Activities
Funcionam como mediadores que definem como as informações serão apresentadas ao
usuário, além de controlar o fluxo da aplicação. Elas podem interagir com o usuário e
trocar informações com outras activities ou services (MEIER,2009).
A maioria do código que escreveremos para uma aplicação Android irá executar
no contexto de uma activity. Activities normalmente correspondem a telas: cada activity
mostra uma tela para o usuário. Quando esta não está em execução, o sistema
operacional pode eliminá-la para liberar memória.
5.3.1.1. Ciclo de vida de uma Activity
Ao longo de sua criação até o momento de sua eliminação da memória, uma activity
atravessará seis estados, podemos referenciar cada estado pelos métodos:
OnCreate
É chamado quando a activity é criada. Ela é obrigatória e chamada apenas uma vez,
deve referenciar a tela que será apresentada ao usuário.
OnStart
É chamado quando a activity está ficando visível e já tem uma tela definida.
OnResume
É chamado quando a activity foi parada temporariamente e está retornando à execução.
OnPause
É chamado quando a activity está sendo tirada do topo da execução. Geralmente é
utilizado para salvar o estado da aplicação.
OnStop
É chamado quando a activity não está mais visível e está em segundo plano.
OnDestroy
Executa os últimos processamentos antes da activity ser literalmente encerrada.
103
Figura 5.2. Ciclo de vida de uma Activity.
5.3.2. Services
São programas que executam em segundo plano. Não interagem diretamente com o
usuário e podem ficar executando por tempo indefinido.
5.3.3. Broadcast e Intent Receivers
São componentes que ficam aguardando a ocorrência de um determinado evento, podese entender como evento a inicialização do sistema operacional, uma chamada de voz, a
chegada de um SMS, um evento disparado por uma aplicação (MEIER,2009).
Intents são elementos chave no Android, porque facilitam a criação de novas
aplicações a partir de aplicações já existentes. Precisaremos utilizar Intents para
interagir com outras aplicações e serviços que proporcionarão informações necessárias
para nossa aplicação.
5.3.4. Content Providers
São os compartilhadores de conteúdo entre as aplicações, uma aplicação pode requisitar
informações de outra, por exemplo, uma aplicação pode receber dados da lista de
contatos que é nativa do Android, e com base nesses dados, realizar algum
processamento (LECHETA,2010).
104
5.4. Android SDK e seus pacotes para implementação de aplicações
O SDK é um conjunto de ferramentas utilizadas para desenvolver aplicações para a
plataforma Android. Possui um emulador para simular o dispositivo móvel e uma API
completa para a linguagem Java, com todas as classes necessárias para desenvolver as
aplicações (BURNETTE, 2008).
Existem atualmente três versões do SDK para atender a maior parte dos
desenvolvedores: versão para Windows, Linux e Mac OS.
O ambiente de desenvolvimento que nos utilizaremos nos exemplos seguintes é
composto, além do JDK e Android SDK, pelo Eclipse IDE versão Galileo e o Android
Development Plugin (ADT), um plugin que ajudará na integração da IDE com o
emulador.
Os componentes do ambiente de desenvolvimento podem ser encontrados nos
links a seguir:

JDK: http://www.oracle.com/technetwork/java/javase/downloads/index.html

Android SDK: http://developer.android.com/sdk/

Eclipse IDE: http://www.eclipse.org/downloads/

ADT: http://developer.android.com/sdk/eclipse-adt.html
5.4.1. Conceitos básicos do Android
5.4.1.1 Criando uma Activity
A classe android.app.activity é utilizada para criar uma tela na aplicação. Essa tela é
composta de vários elementos visuais, os quais no Android são representados pela
classe android.view.View (LECHETA, 2010).
A classe android.view.View pode representar algo simples como um botão, um
checkbox ou imagem, como também pode representar algo complexo como um
gerenciador de layout, a qual pode conter várias views aninhadas para organizar na tela.
Figura 5.3. Exemplo de uma Activity.
O método setContentView(view) é o que faz a ligação entre a activity e a view e
recebe como parâmetro a view que será exibida na tela.
105
5.4.1.2 A classe R
A classe R é criada automaticamente pelo ADT e não pode ser alterada manualmente.
Nela existem constantes para os recursos do projeto. Cada constante é nomeada com o
nome do recurso, que deve ser escrito com letra minúscula e sem espaço, e recebe um
valor inteiro.
5.4.1.3 O arquivo AndroidManifest.xml
Toda aplicação Android deve ter um arquivo AndroidManifest.xml em seu diretório raiz.
Esse arquivo apresenta informações essenciais sobre a aplicação para o sistema
operacional, que deve possuir informações do sistema antes que possa executar qualquer
solicitação do código do aplicativo (MEDNIEKS,2009).
Ele armazena informações como o nome do pacote da aplicação, descreve os
componentes da aplicação, determina qual processo da aplicação vai armazenar os
componentes, declara de que formas as solicitações devem ter permissões para acessar
partes protegidas da API e interagir com outras aplicações. Declara também as
permissões que os outros processos serão obrigados a ter, fim de interagir com os
componentes da aplicação, enumera classes e perfis e fornece outras informações sobre
como a aplicação será executada, declara qual o nível mínimo da API que o aplicativo
exige e enumera bibliotecas que estarão relacionadas com a aplicação.
Figura 5.4. Exemplo de arquivo AndroidManifest.xml
5.4.1.4 Criação de uma interface visual
O Android fornece um sofisticado e poderoso modelo, baseado em componentes, para
construir sua interface, baseado no esquema de classes fundamentais:
android.view.View e android.view.ViewGroup, e inclui também as suas classes filhas
chamadas de widgets e layouts respectivamente(LECHETA, 2010).
Podemos citar alguns exemplos de widgets como Button, TextView, EditText,
ListView, CheckBox, RadioButton, Gallery, Spinner, e outros.
Podemos citar, também, exemplos de layouts como LinearLayout, FrameLayout,
RelativeLayout entre outros.
Para exemplificar a criação da interface visual criaremos uma tela de login, a
qual conterá os campos de nome de usuário e senha, e um botão para submetê-los.
106
Figura 5.5. Representação gráfica da tela de login.
Figura 5.6. Código da tela de login
107
Podemos observar que foram utilizados três tipos de widgets e um layout. Dois
TextView que são utilizados para renderizar strings na tela e dois EditText que são
caixas para receber texto. Foi utilizado, também, um “Button” para enviar os dados e
um LinearLayout para organizá-los na tela.
Podemos observar, também, alguns atributos como o “id” que serve como
identificador de cada componente, o text que tem o funcionamento semelhante ao value
do HTML e o atributo password que esconde os caracteres digitados no nosso EditText.
5.4.1.5 O método findViewById()
Ao construir uma tela usando um arquivo XML de layout, surge a necessidade de
recuperar os objetos definidos no arquivo dentro do código-fonte da aplicação para obter
seus valores ou definir atributos (LECHETA, 2010).
Podemos recuperar um objeto de visão através do seu identificador único
(android:id), passando-o como parâmetro no método findViewById(id). Esse método
recebe o id do componente desejado e retorna uma subclasse de android.view.View,
como as classes Button, TextView e EditText.
Na figura a seguir é mostrado como recuperar a senha inserida pelo usuário
através do método findViewById(id) e uma pequena ajuda da classe R.
Figura 5.7. Exemplo da utilização do método findViewById()
5.4.2 Intent
Uma intent representa uma intenção da aplicação em realizar alguma ação. Ela envia
uma mensagem ao sistema operacional chamada de broadcast. Ao receber essa
mensagem, o sistema operacional tomará as decisões necessárias (LECHETA, 2010).
108
Uma intent é representada pela classe android.content.Intent e pode ser
utilizada para enviar uma mensagem ao sistema operacional, abrir uma nova tela da
aplicação, utilizando o método startActivity(intent), solicitar ao sistema operacional que
ligue para determinado número de celular, abrir o browser em um determinado endereço
da internet, exibir algum endereço, localização ou rota no Google Maps dentre outros.
5.4.2.1 Navegação entre telas com passagem de parâmetros
Existem dois métodos de se iniciar uma nova tela (activity), através dos métodos
startActivity(intent) e startActivityForResult(intent,codigo) que apenas inicia uma nova
activity ou inicia uma nova activity e cria um vínculo para ser utilizado ao retornar
respectivamente (PEREIRA, 2009).
Para que o sistema operacional possa reconhecer nossa nova activity, é
necessário adicionar seu endereço no arquivo AndroidManifest.xml.
Figura 5.8. Trecho do arquivo AndroidManifest.xml que contém a nova activity.
Podemos enviar informações para outras telas através de uma intent.
Figura 5.9. Exemplo de passagem de parâmetro e troca de tela através de uma intent
Podemos observar na figura 5. 8, que é criada uma intent com a activity da telaalvo, é passado como parâmetro através do método putExtra() o texto contido no
EditText referente ao usuário para a próxima tela, e finalmente, a nova activity é
iniciada através do método startActivity(intent).
109
Figura 5.10. Código da classe SegundaTela.
Observando essa classe, vemos que a intent é capturada através do método
getIntent() e recebemos o parâmetro do login através do método getStringExtra(string).
O conteúdo da tela é apenas um TextView com uma mensagem de boas vindas.
5.4.2.2 Intents Nativas do Android
Vimos no exemplo anterior que é possível iniciar uma nova activity através das intents.
O Android possui alguns tipos de intents pré-definidas que podemos utilizar para enviar
mensagens ao SO, porém, algumas delas necessitam de permissões para executar, tais
permissões precisam ser registradas no arquivo AndroidManifest.xml (PEREIRA,2009).
Várias intents como a ACTION_VIEW, que serve para iniciar o navegador, a
ACTION_CALL, que é utilizada para realizar chamadas, a ACTION_PICK, que serve
para visualizar todos os contatos, dentre outras, são utilizadas em aplicações Android.
A seguir veremos um exemplo de como chamar o navegador através de uma
intent pré-definida no Android.
Figura 5.11. Exemplo da iniciação do navegador através de uma Intent.
O exemplo demonstra a utilização da intent ACTION_VIEW, mas, para usar
essa intent é necessária a permissão INTERNET que deve ter sido registrada
previamente.
Figura 5.12. Inserindo a permissão INTERNET no arquivo AndroidManifest.xml
110
5.4.3 Intent Filter
Podemos utilizar intents para enviar mensagens ao sistema operacional, definindo uma
ação que identifique essa intent. Então quando a mensagem for enviada ao sistema
operacional ela seja identificada por essa ação, e somente uma activity que esteja
mapeada para aquela ação será executada (MEDNIEKS, 2009).
Esse tipo de rotina é bem prática quando queremos que mais de um programa
esteja configurado para receber uma ação (LECHETA, 2010).
Para definir essa ação, basta criar uma Intent usando seu construtor, que recebe
uma string que identifica a ação, como, por exemplo:
Figura 5.13. Exemplo de uma chamada de ação por uma Intent.
Logicamente, alguém tem que responder por essa ação. Para isto, precisamos
mapear um Intent Filter no arquivo AndroidManifest.xml, para escutar esse chamado e
delegar a execução à uma activity.
Figura 5.14. Código fonte da classe SegundaTela.
Figura 5.15. Exemplo de mapeamento de uma Intent Filter.
5.4.4 BroadcastReceiver
A classe BroadcastReceiver é utilizada para responder a determinados eventos enviados
por uma intent. Ela sempre é executada em segundo plano durante pouco tempo,
normalmente dez segundos. Não deve ter interface gráfica ou interação com o usuário
(LECHETA, 2010).
111
É utilizada normalmente para executar algum processamento sem que o usuário
perceba, em segundo plano.
Assim como uma activity, devemos declará-lo no arquivo AndroidManifest.xml
através da tag <receiver>, deve ser declarada, também, um Intent Filter para o broadcast,
ou
podemos
registrá-lo
dinâmicamente,
utilizando
o
método
registerReceiver(receiver,filtro), que tem como parâmetros uma classe-filha de
IntentReceiver e uma instância da classe IntentFilter que possui a configuração da ação e
a categoria (LECHETA, 2010).
O método para enviar uma mensagem para um broadcast é diferente do utilizado
para uma intent que chama uma activity. O método utilizado é o sendBroadcast(intent)
que envia uma mensagem para todas as aplicações instaladas no celular.
Para implementar um BroadcastReceiver deve-se extender a classe
BroadcastReceiver e implementar o método onReceive() que será executado assim que o
IntentFilter receber a mensagem.
Figura 5.16. Utilizando o método sendBroadcast(intent).
112
Figura 5.17. Exemplo de um BroadcastReceiver.
Apenas por motivos didáticos foi utilizado a classe Toast para verificar o funcionamento
do BroadcastReceiver. Recomenda-se que não tenha nenhum tipo de interação com o
usuário.
Figura 5.18. Exemplo do mapeamento de um BroadcastReceiver.
5.4.5 Notification
A classe Notification é utilizada para exibir informações ao usuário sem que este seja
interrompido se estiver executando alguma atividade. O usuário pode escolher visualizar
as informações neste momento, ou depois (LECHETA, 2010).
A notificação é exibida na barra de status do celular para chamar a atenção do
usuário. Ao ser visualizada, a intent configurada pode uma abrir uma nova activity ou
pode ser usada para iniciar um serviço por exemplo (MEIER, 2009).
Um exemplo de notificação é a recepção de uma nova SMS, onde usuário pode
decidir visualizá-la ou não.
Para criar uma notificação é necessário capturar um serviço do Android chamado
de NOTIFICATION_SERVICE, será necessário, também utilizar a classe PendingIntent
que criará uma intent que ficará pendente até o usuário decidir visualizar a notificação:
113
Figura 5.19. Exemplo da criação de uma notificação.
Podemos observar, que o construtor da classe Notification recebe três
parâmetros: o ícone que deverá ser exibido, o título da notificação e a hora que
aparecerá do lado da notificação.
Observamos, também, que deve-se informar através do método
setLatestEventInfo, a mensagem que aparecerá na barra de status assim que a
notificação for reconhecida pelo serviço de notificações do android, o título da
notificação e a intent que deverá ser chamada quando o usuário visualizar a notificação.
Figura 5.20. Classe que será instanciada quando a notificação for visualizada.
A figura anterior mostra a classe que será instanciada quando o usuário
visualizar a notificação. Capturamos o serviço de notificações do android, e pedimos
114
para que a notificação não apareça mais na barra de status através do método cancel(int)
que recebe como parâmetro o id da notificação.
5.4.6 Service
Têm as mesmas características dos serviços dos sistemas operacionais de computador.
São utilizados quando queremos executar algo por tempo indeterminado em
segundo plano e que exija um alto consumo de recursos, memória e CPU (LECHETA,
2010).
Geralmente são iniciados por um BroadcastReceiver para executar algum
processamento demorado, pois um BroadcasReceiver tem um tempo determinado para
executar (PEREIRA, 2009).
É interessante que os serviços tenham suas próprias threads para que fiquem
independentes do programa hospedeiro. Eles também possuem um ciclo de vida próprio,
semelhante ao de uma Activity, mas possuem apenas três estágios: o onCreate, onStart e
onDestroy, que desempenham o mesmo papel que o de uma Activity.
Para iniciar um serviço é necessário criar uma activity que chame o método
startService(intent). Para parar um serviço existem duas maneiras: a primeira é chamar o
método stopService(intent), a mesma intent utilizada para iniciar o serviço deve ser
usada para pará-lo, e a segunda forma é o próprio serviço chamar o método stopSelf().
Figura 5.21. Chamando um serviço.
Para implementar um serviço é necessário estender a classe android.
115
Figura 5.22. Exemplo de um serviço.
Para exemplificar o funcionamento de um serviço, utilizamos esta classe, que
quando iniciada, cria uma série de logs. Podemos observar que mesmo fechando a
aplicação que iniciou o serviço, ele continua criando logs até chamar o método
stopSelf().
É necessário mapear o serviço no arquivo AndroidManifest.xml e configurar um
IntentFilter com a ação que iremos passar como parâmetro pela nossa Intent.
116
Figura 5.23. Exemplo do mapeamento de um serviço.
5.4.7 AlarmManager
São eventos agendados no sistema operacional para serem executados no futuro
(LECHETA, 2010).
É utilizado quando é necessário executar algo uma vez em determinado horário
ou ficar repetindo de tempos em tempos.
Quando agendados, ficam ativos no sistema até que sejam explicitamente
cancelados, ou o sistema for reiniciado.
Para agendar um alarme, primeiro temos que definir uma intent com o
BroadcastReceiver que irá responder pelo nosso alarme. Depois temos que capturar o
serviço do Android responsável pelo gerenciamento dos alarmes, o AlarmManager.
Figura 5.24. Agendando um alarme.
117
Figura 5.25. BroadcastReceiver que será chamado pelo nosso alarme.
5.5. Arquitetura REST de desenvolvimento de aplicações Web
Vivemos hoje uma febre de Apps – pequenos aplicativos auto-contidos que tem uma
única função e comumente são interfaces para sistemas Web. A maioria desses
aplicativos é extremamente dependente de dados para serem úteis e esses dados podem
vir dos mais variados lugares – por exemplo, a plataforma Android disponibiliza ao
desenvolvedor uma pequena base dados SQLite onde ele pode criar suas tabelas,
armazenar e buscar dados, mas cada vez mais esses dados vêm de serviços web.
A Web é uma plataforma “orientada a recursos”. Um Recurso pode ser definido
como qualquer coisa que é exposta a Web através de um identificador e que possamos
manipular (ler e/ou escrever) (WEBBER; PARASTATIDIS, 2010)..
Desde sua formalização REST1 vem sendo um termo e, mais adequadamente,
uma arquitetura de software de sistemas Web cada vez mais utilizado, estudado e
discutido. Esta arquitetura foi proposta pelo Dr. Roy T. Fielding em 2000 e desde então
vem sendo adotada em vários sistemas de grande porte como Twitter, Facebook, Flickr
e todas as APIs de serviços públicos do Google como Google Agenda, Google Health,
Google Data e Google Maps.
Veremos a seguir o que é REST e, em seguida, formas de se trabalhar com
REST em Java.
5.5.1 Definição
O protocolo HTTP, e consequentemente servidores HTTP, é um protocolo simples e
sem muitos recursos. Em sua primeira versão ele apresentou endereçamento e
statelessness: duas características de seu projeto que o tornou um avanço perante seus
rivais e que ainda o mantém escalável mesmo nos mega-sites de hoje (RICHARDSON;
RUBY, 2007).
Sistemas com esta arquitetura são sistemas Clientes-Servidores comuns,
entretanto suas requisições e respostas são construídas ao redor da transferência da
representação de recursos. Recursos são os blocos fundamentais de sistemas baseados
na web, ao ponto que a Web é considerada como “orientada a recursos” (WEBBER;
PARASTATIDIS, 2010). A abstração chave de informação do REST são os recursos.
Qualquer informação que pode ser nomeada pode ser um recurso: documentos, imagens,
informações sobre o tempo, uma pessoa, e assim sucessivamente (FIELDING, 2000).
1
Representational State Transfer – Transferência de Estado Representacional
118
Um dos recursos mais comuns da Web são páginas HTML, que em sistemas são
comumente a representação de um recurso interno do sistema, por exemplo, uma página
de exibição de um vídeo do YouTube é a representação do recurso “vídeo” do sistema.
Um mesmo recurso pode ter várias representações diferentes. Utilizando o
exemplo do vídeo do YouTube, uma representação é a página HTML onde é mostrado o
vídeo, comentários, etc. outra representação é vista quando o vídeo é incorporado em
outra página. Nessa representação vemos apenas um player que carrega o vídeo em
questão. Outra representação, um pouco menos conhecida, é a representação em XML2
ou mais recentemente JSON3, ambas tecnologias de transição de dados hierárquicos.
Devido a essas características REST também requer que as aplicações façam
total distinção entre cliente e servidor através da implementação das seguintes
características:
1.
Cliente-Servidor: Clientes são separados dos Servidores por uma interface
uniforme. Essa divisão faz com que o cliente não se preocupe com, por exemplo,
armazenamento de dados ao passo que o servidor não se preocupa com interface
com o usuário;
2.
Stateless (Sem Estado): A comunicação cliente-servidor ocorre sem que nenhum
contexto relativo ao cliente seja armazenado no servidor entre as requisições.
Cada requisição de cada cliente contém toda informação necessária para atender
aquela requisição e a reposta deve conter toda a informação para satisfazer a
requisição;
3.
Cache: Como é comum na Web, o cliente pode manter um cache das respostas do
servidor, portanto é recomendado que as respostas contenham informações sobre
se podem e como deve ser feito o cache a fim de evitar que clientes requisitem um
mesmo recurso repetidamente. Um bom cache elimina várias interações clienteservidor desnecessárias o que proporciona escalabilidade e performance;
4.
Camadas: Um cliente não pode normalmente distinguir se ele está ou não
conectado ao servidor final ou apenas a um intermediário. Um sistema com vários
servidores permite o balanceamento de carga, caches compartilhados e ajudam a
manter uma boa segurança;
5.
Código sob demanda (opcional): Servidores podem ser capazes de estender a
funcionalidade de um cliente transferindo lógica para que ele execute. Exemplos
disso são componentes compilados como Applets Java ou scripts no lado cliente
como JavaScript;
6.
Interface uniforme: Todo cliente obedece ao mesmo formato de requisição e
recebe o mesmo formato de resposta.
2
3
XML – eXtensible Markup Language – Linguagem de marcação extensível.
JavaScript Object Notation – Notação de Objetos JavaScript.
119
A arquitetura REST está fundamentada sob o protocolo HTTP e seus métodos.
Clientes que acessam recursos informando sua intenção através do método que
executam sob o recurso. A maioria dos sistemas hoje em dia segue a seguinte convenção
de métodos HTTP, concebidos para simular operações de CRUD:

GET: Leitura;

POST: Escrita;

PUT: Alteração ou Atualização;

DELETE: Remoção.
Muitas aplicações novas estão utilizando os princípios REST a fim de obterem
um bom nível de escalabilidade. Normalmente essas aplicações disponibilizam a seus
usuários uma API dos métodos REST disponíveis, suas entradas e suas saídas.
Para compreender melhor, vejamos a API de um sistema referência em
tecnologia REST: o Twitter.
O Twitter disponibiliza em seu website uma extensa e detalhada documentação
da API de seu sistema4. uma plataforma de apoio aos desenvolvedores que desejam criar
clientes para o Twitter com páginas de ajuda onde são descritos os métodos da API, um
guia ao desenvolvedor e ferramentas para ajudá-lo.
Chamadas a alguns métodos da API podem ser feitas, para testes, através de um
navegador web qualquer.
Durante a escrita deste texto, a API do Twitter aceita a seguinte chamada:
http://api.twitter.com/1/users/show.xml?screen_name=fat. Para
chamar este método da API basta abrir esta URL em qualquer navegador web.
Ao abrir esta URL em um navegador, o que é feito é uma chamada a API através
do método HTTP GET. Chamadas a qualquer API REST na Web são compostas de 3
partes:
1. A URL correspondente ao método da API
 http://api.twitter.com/1/users/show
2.
Os parâmetros da chamada ao método
 screen_name = fat
3.
O método HTTP utilizado para chamada aquela URL
 Por padrão, toda transação HTTP dos navegadores atuais utiliza o método GET.
A URL é uma chamada ao método “1/users/show” da API do Twitter. Uma
particularidade dessa API é a possibilidade de escolha do formato de representação do
recurso: XML ou JSON, representado pela “extensão do arquivo” na URL.
4
Disponível em http://dev.twitter.com/ - Acesso em 12 outubro 2011
120
5.5.2. REST em Java
Em Java chamadas a APIs REST são feitas utilizando chamadas HTTP simples,
normalmente com objetos java.net.URL e java.net.HttpURLConnection.
Nos exemplos a seguir utilizaremos a API do Twitter como exemplo.
A forma mais simples de se executar uma chamada é a seguinte:
String apiCall = "<url de chamada a API>";
URL url = new URL(apiCall);
HttpURLConnection conn;
conn = (HttpURLConnection) url.openConnection();
Ao invocar o método openConnection() uma requisição HTTP GET é feita
a URL especificada em apiCall. Após essa chamada, é importante verificar o código
de resposta dado pelo servidor. Normalmente um código de resposta 200 significa que
tudo ocorreu como esperado. Outros códigos de resposta podem ser especificados pela
API.
if (conn.getResponseCode() == 200) {
// Tudo ocorreu como esperado.
}
Dessa forma podemos tomar alguma providência caso ocorra algum erro, e
garantir um bom funcionamento da aplicação.
Após a confirmação do sucesso da chamada o próximo passo é ler os dados da
resposta do servidor. É necessário um cuidado especial com o tipo de dado esperado
pois a resposta da API pode ser uma imagem, ou um documento, ou até mesmo um
Stream de dados. Vamos considerar que a resposta a nossa chamada está em formato
textual, caso qual podemos utilizar a seguinte técnica para captar o resultado num
formato mais cômodo para manipulação:
BufferedReader
reader
=
new
BufferedReader(new
InputStreamReader(conn.getInputStream()));
StringBuilder str = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
str.append(line);
}
reader.close();
Após o recebimento da resposta, é uma boa prática sempre fechar a conexão
junto ao servidor invocando o método disconnect():
conn.disconnect();
Dessa forma podemos fazer chamadas a quaisquer API REST utilizando Java.
121
5.5.2.1 Interpretando Respostas
Em Java podemos quase sempre considerar um recurso disponibilizado pelo servidor
com um Objeto. Comumente recebemos respostas em XML o qual é uma serialização
de um objeto que está no servidor.
Devido a isso um ponto que requer especial atenção é a interpretação das
respostas. APIs REST utilizam representações do estado de um recurso (um Objeto) do
sistema. Nestes casos a forma mais comum de representação é textual, segundo um
padrão determinado pela API, XML ou JSON.
Existem várias bibliotecas disponíveis para se trabalhar com os formatos XML e
JSON, algumas bastante sofisticadas e simples de usar. Para XML temos, por exemplo,
uma biblioteca chamada jDOM5 que interpreta XML e dá ao desenvolvedor uma
representação do documento XML na forma de um grafo de objetos com uma interface
nativa Java que podem ser facilmente percorridos e manipulados. Para JSON há uma
biblioteca chamada Gson6 disponibilizada pelo Google que pode transformar Objetos
Java em sua representação JSON e vice-versa:
Gson gson = new Gson();
String json = gson.toJson(meuObjeto);
MeuObjeto obj = gson.fromJson(json, MeuObjeto.class);
Através do uso de bibliotecas auxiliares é possível criar objetos concretos Java a
partir de representações textuais dos mesmos.
A utilização de JSON é recomendada nestes casos pois grande parte dos sistemas
REST atuais são voltados para a interatividade entre sistemas de Websites, os quais são
em sua maioria feitos utilizando JavaScript, linguagem-mãe da notação JSON e que dá
suporte nativo a interpretação e construção de objetos a partir de sua representação
textual e vice-versa.
Referências bibliográficas
ABLESON, W. Frank; Unlocking Android - A Developer’s Guide. Ed. Manning, 2007.
BURNETTE, Ed.Hello, Android:Introducing Google`s Mobile Development Plataform.
Pragmatic Bookshelf, 2008.
Google Android. Disponível em <http://developer.android.com/guide/basics/what-isandroid.html>. Acesso em 12 outubro 2011.
LECHETA, Ricardo R. Google Android. São Paulo: Novatec, 2010, 2 ª ed.
MEDNIEKS, Zigurd; MEIKE, Blake. Desenvolvimento de Aplicações Android. São
Paulo: Novatec, 2009, 1ª ed.
MEIER, Reto. Professional Android Application Development. Indianapolis: Wiley
Publishing, 2009, 1ª. ed.
5
6
http://www.jdom.org/ - Acesso em 12 outubro 2011
http://code.google.com/p/google-gson/ - Acesso em 12 outubro 2011
122
PEREIRA, Lúcio C. Oliva. Android para Desenvolvedores. São Paulo: Brasport, 2009,
1ª ed.
WEBBER, Jim; PARASTATIDIS, Savas; ROBINSON Ian. REST in Practice:
Hypermidia and Systems Architecture. O’Reilly Media, 2010.
RICHARDSON, Leonard; RUBY Sam. RESTful web services. O’Reilly Media, 2007.
FIELDING, Roy; Architectural Styles and the Design of Network-based Software
Architectures. Dissertação de Doutorado, University of California, 2000.
123
Capítulo
6
Desenvolvendo aplicações multi-tenancy para
computação em núvem
Josino Rodrigues Neto, Vinícius Cardozo Garcia e Wilton dos Santos
Oliveira
Abstract
This course focuses on presenting the main concepts of multi-tenancy and use a
practical approach to demonstrate the implementation of an application based on a
multi-tenancy architecture. Thus, this chapter presents the definitions and key
characteristics of cloud computing, SaaS service model and a multi-tenancy approach
for SaaS.
Resumo
Este minicurso tem como foco principal apresentar os principais conceitos de multitenancy e utilizar uma abordagem prática para demonstrar a implementação de uma
aplicação baseada em uma arquitetura multi-tenancy. Assim, este capítulo apresenta as
definições e as características essenciais da computação em nuvem, o modelos de
serviço SaaS e uma abordagem multi-tenancy para SaaS.
6.1 Introdução
Com o ritmo de desenvolvimento da sociedade humana moderna, serviços básicos e
essenciais são quase todos entregues de uma forma completamente transparente.
Serviços de utilidade pública como água, eletricidade e telefone tornaram-se
fundamentais para nossa vida diária e são explorados através de um modelo de
pagamento baseado no uso. As infraestruturas existentes permitem entregar os serviços
em qualquer lugar e a qualquer hora, de forma que possamos simplesmente acender a
luz, abrir a torneira ou fazer uma ligação para qualquer lugar. O uso desses serviços é
cobrado de acordo com as diferentes políticas para o usuário final. A mesma idéia de
124
utilidade tem sido aplicada na área da informática e uma mudança consistente neste
sentido tem sido feita com a disseminação da computação em nuvem.
Segundo o NIST, Cloud Computing(Computação em núvem) é composta por
cinco características essenciais: self-service sob demanda; amplo acesso a rede; pooling
de recursos; elasticidade rápida. Ainda segundo o NIST, Cloud Computing é dividido
em três modelos de serviço: Software como serviço (SaaS); Plataforma como serviço
(PaaS); Infraestrutura como Serviço (IaaS).
Nesse contexto, este minicurso tem como foco principal apresentar os principais
conceitos de multi-tenancy e utilizar uma abordagem prática para demonstrar a
implementação de uma aplicação baseada em uma arquitetura multi-tenancy. Assim,
este capítulo apresenta as definições e as características essenciais da computação em
nuvem, o modelos de serviço SaaS e uma abordagem multi-tenancy para SaaS.
Este capítulo está organizado no seguinte formato:

A seção 1.2apresenta os conceitos fundamentais de cloud computing, Software
como serviço e Multi-tenancy.

A seção 1.3 apresenta os componentes de uma arquitetura multi-tenancy.

A seção 1.4 apresenta o passo a passo para a implementação de um protótipo de
aplicação multi-tenancy com Grails.
Finalmente, a seção 1.5 apresenta as conclusões finais.
6.2 Conceitos Fundamentais
6.2.1 Cloud Computing
.1
Na computação em nuvem os recursos de TI são fornecidos como um serviço,
permitindo aos usuários o acessa-los sem a necessidade de conhecimento sobre a
tecnologia utilizada. Assim, os usuários e as empresas passaram a acessar os serviços
sob demanda e independente de localização, o que aumentou a quantidade de serviços
disponíveis. Computação em nuvem pretende ser global e prover serviços para todos,
desde o usuário final que hospeda seus documentos pessoais na Internet até empresas
que terceirizarão toda a parte de TI para outras empresas.
Mas o que é Cloud Computing? Segundo Taurion o termo computação em
nuvem surgiu em 2006 em uma palestra de Eric Schmidt, da Google, sobre como sua
empresa gerenciava seus data centers. Hoje, computação em nuvem, se apresenta como
o cerne de um movimento de profundas transformações do mundo da tecnologia
(TAURION, 2009).
Segundo o NIST(National Institute of Standards and Technology) , Cloud
Computing é composta por cinco características essenciais:
125

Self-service sob demanda: O usuário pode adquirir unilateralmente recurso
computacional, como tempo de processamento no servidor ou armazenamento
na rede na medida em que necessite e sem precisar de interação humana com os
provedores de cada serviço.

Amplo acesso a rede: recursos estão disponíveis através da rede e acessados por
meio de mecanismos que promovam o padrão utilizado por plataformas
heterogêneas (por exemplo, telefones celulares, laptops e PDAs).

Pooling de recursos: o provedor de recursos de computação são agrupados para
atender vários consumidores através de um modelo multi-tenant, com diferentes
recursos físicos e virtuais atribuídos dinamicamente e novamente de acordo com
a demanda do consumidor. Há um senso de independência local em que o cliente
geralmente não tem nenhum controle ou conhecimento sobre a localização exata
dos recursos disponibilizados, mas pode ser capaz de especificar o local em um
nível maior de abstração (por exemplo, país, estado ou data center). Exemplos de
recursos incluem o armazenamento, processamento, memória, largura de banda
de rede e máquinas virtuais.

Elasticidade rápida: recursos podem ser adquiridos de forma rápida e elástica,
em alguns casos automaticamente, caso haja a necessidade de escalar com o
aumento da demanda, e liberados, na retração dessa demanda. Para os usuários,
os recursos disponíveis para uso parecem ser ilimitados e podem ser adquiridos
em qualquer quantidade e a qualquer momento.

Serviço medido: sistemas em nuvem automaticamente controlam e otimizam a
utilização dos recursos, alavancando a capacidade de medição em algum nível de
abstração adequado para o tipo de serviço (por exemplo, armazenamento,
processamento, largura de banda, e contas de usuários ativos). Uso de recursos
pode ser monitorado, controlado e relatado a existência de transparência para o
fornecedor e o consumidor do serviço utilizado.
Ainda segundo o NIST, Cloud Computing é dividido em três modelos de
serviço:

Software como Serviço (Software as a Service - SaaS): A capacidade fornecida
ao consumidor é usar as aplicações do fornecedor que funcionam em uma
infraestrutura da nuvem. As aplicações são acessíveis dos vários dispositivos do
cliente através de uma relação do thin client tal como um browser web. O
consumidor não administra ou controla a infraestrutura básica, incluindo nuvens
de rede, servidores, sistemas operacionais, armazenamento, ou mesmo
capacidades de aplicação individual, com a possível exceção de limitada
aplicação específica e definições de configuração de usuários da aplicação.

Plataforma como Serviço (Plataform as a Service - PaaS): A capacidade
fornecida ao consumidor é desdobrar na nuvem a infraestrutura consumidor
criada ou as aplicações adquiridas criadas usando linguagens de programação e
as ferramentas suportadas pelo fornecedor. O consumidor não administrar ou
126
controlar a infraestrutura básica, incluindo nuvens de rede, servidores, sistemas
operacionais, ou armazenamento, mas tem controle sobre os aplicativos
utilizados e eventualmente hospedagem de aplicativos e configurações de
ambiente.

Infraestrutura como Serviço (Infraestructure as a Service - IaaS) : A
capacidade prevista para o consumidor é a prestação de transformação,
armazenamento, redes e outros recursos computacionais fundamental que o
consumidor seja capaz de implantar e executar programas arbitrários, que podem
incluir sistemas operacionais e aplicativos. O consumidor não administra ou
controla a infraestrutura de nuvem subjacente, mas tem controle sobre os
sistemas operacionais, armazenamento, aplicativos implantados, e,
eventualmente, o controle limitado de componentes de rede selecionar (por
exemplo, firewalls host).
Esse trabalho não pretende abordar exaustivamente todos os modelos de serviço
de Cloud Computing, esse trabalho tem como foco principal SaaS, especificamente a
aplicação da arquitetura multi-tenancy.
6.2.2 Software como Serviço(SaaS)
.1
Por décadas, as companhias utilizavam seu software em sua própria infraestrutura e
eram responsáveis por todas as atividades de manutenção, integridade, escalabilidade,
disponibilidade e uma série de encargos relacionados ao gerenciamento de TI na
empresa. Além de custos relacionados à compra de licenças e atualizações, as empresas
tinham que adequar sua infraestrutura e contratar pessoas especializadas para as
atividades de gerenciamento.
Foi nesse contexto que surgiu o conceito de SaaS. Neste modelo, a
funcionalidade da aplicação é oferecida através de um modelo de assinatura pela
Internet. O cliente não se torna dono do software, ao invés disso, ele aluga a solução
total que é oferecida remotamente.
Podemos dividir as aplicações de software como serviço em duas categorias
(CHONG e CARRARO, 2006):
 Serviços para linha de negócios (line-of-business): oferecidos a
empresas e organizações de todos os tamanhos. Os serviços de linha de negócios
geralmente são soluções de negócios grandes e personalizáveis direcionadas para
facilitar processos de negócios como finanças, gerenciamento da cadeia de
suprimentos e relações com o cliente. Normalmente esses serviços são vendidos
aos clientes como assinatura. Um exemplo desse tipo de serviço são as soluções
personalizáveis do Salesforce (SALESFORCE, 2000).
 Serviços orientados ao consumidor: oferecidos ao público em geral.
Os serviços orientados a cliente às vezes são vendidos como assinatura, mas
geralmente são fornecidos sem custo e financiados por anúncios. Um outro
127
exemplo desse tipo de serviço são os serviços oferecidos pelo Google(Gmail,
Google docs, Google Agenda, etc).
Apesar do conceito de SaaS não ser uma coisa nova, esse conceito ganhou força
somente por volta de 2005 e 2006 com o surgimento e viabilidade de uso de novas
tecnologias como web 2.0, rich internet application(RIA), SOA, cloud computing,
virtualização, etc. Implementar o conceito de SaaS nem sempre é tão simples como
parece. Chong (CHONG e CARRARO, 2006) propõe 4 níveis de maturidade para
aplicações que utilizam o modelo de SaaS:
Figura 6.1 - Níveis de Maturidade SaaS (CHONG e CARRARO, 2006)

Nível 1 – Ad-Hoc/Personalizado: O primeiro nível de maturidade é semelhante
ao modelo de entrega de software do provedor de serviços de aplicativos (ASP)
tradicional, que data da década de 1990. Nesse nível, cada cliente tem a sua
própria versão personalizada do aplicativo hospedado e executa a sua própria
instância do aplicativo nos servidores do host. Pensando em arquitetura, software
nesse nível de maturidade é muito semelhante ao software de linha de negócios
vendido tradicionalmente, em que diferentes clientes em uma organização
conectam a uma instância única em execução no servidor, mas essa instância é
totalmente independente de quaisquer outras instâncias ou processos que o host
esteja executando para os seus outros clientes.

Nível 2 – Configurável: No segundo nível de maturidade, o fornecedor hospeda
uma instância separada do aplicativo para cada inquilino enquanto que no
128
primeiro nível cada instância é personalizada individualmente para o inquilino,
neste nível todas as instâncias utilizam a mesma implementação de código e o
fornecedor atende as necessidades dos clientes fornecendo opções de
configuração detalhadas que permitem ao cliente alterar a aparência e o
comportamento do aplicativo para os seus usuários. Apesar de serem idênticas
umas às outras no nível do código, cada instância permanece totalmente isolada
de todas as demais.

Nível 3 – Configurável e eficiente para vários tenants: No terceiro nível de
maturidade, o fornecedor executa uma única instância que serve a todos os
clientes, com metadados configuráveis fornecendo uma experiência de usuário e
conjunto de recursos exclusivos para cada um. Políticas de autorização e de
segurança garantem que os dados de cada cliente sejam mantidos separados dos
de outros clientes e que, da perspectiva do usuário final, não exista qualquer
indicação de que a instância do aplicativo esteja sendo compartilhada entre
vários tenants.

Nível 4 – Escalonável, configurável e eficiente para vários tenants: No quarto e
último nível de maturidade, o fornecedor hospeda vários clientes em um
ambiente com carga balanceada de instâncias idênticas, com os dados de cada
cliente mantidos separados e com metadados configuráveis fornecendo uma
experiência do usuário e um conjunto de recursos exclusivos para cada cliente.
Um sistema de SaaS é escalonável para um número de clientes arbitrariamente
grande, uma vez que a quantidade de servidores e instâncias no lado do
fornecedor pode ser aumentada ou diminuída conforme necessário para
corresponder à demanda sem a necessidade de remodelar a arquitetura aplicativo,
além do que as alterações ou correções podem ser transmitidas para milhares de
tenants tão facilmente quanto para um único tenant.
Normalmente se esperaria que o quarto nível fosse a meta definitiva para
qualquer aplicativo de SaaS, mas não é sempre assim. É necessário verificar as
necessidades operacionais, arquiteturais e de negócio relacionadas à aplicação. Uma
abordagem single-tenant faz sentido financeiramente? O seu aplicativo pode ser feito
para executar em uma única instância lógica? Você pode garantir os seus contratos de
nível de serviço (SLAs) sem isolamento das aplicações? Essas são questões que devem
ser respondidas quando se pretende adotar o modelo SaaS.
6.2.3 Multi-tenancy
.1
Multi-tenancy é uma abordagem organizacional para aplicações SaaS. Bezemer
(BEZEMER e ZAIDMAN, 2010) define multi-tenancy como aplicações que permitem
o compartilhamento dos mesmos recursos de hardware, através do compartilhamento da
aplicação e da instância do banco de dados, enquanto permite configurar a aplicação
para atender às necessidades do cliente como se estivesse executando em um ambiente
dedicado. Tenant é uma entidade organizacional que aluga uma aplicação multi-tenancy.
Normalmente, um tenant agrupa um número de usuários que são os stakeholders da
organização.
129
A definição acima foca no que nós consideramos aspectos em aplicações multi-tenancy:

Possibilidade de compartilhamento de recursos de hardware, permitindo a
redução de custos (HU WANG, JIE GUO, et al., 2008) (WARFIELD, 2007).

Alto grau de configurabilidade, permitindo que cada consumidor customize sua
própria interface e seu workflow na aplicação (NITU, 2009)(JANSEN,
HOUBEN e BRINKKEMPER, 2010).

Uma abordagem arquitetural na qual os tenants fazem uso de uma única
aplicação e banco de dados (KWOK, NGUYEN e LAM, 2008).
Como multi-tenancy é um conceito relativamente novo, é muito comum as
pessoas confundirem multi-tenancy com outros conceitos já existentes. Multi-tenancy
não é multi-usuário. Em uma aplicação multi-usuário nós assumimos que os usuários
estão usando a mesma aplicação com opções de acesso limitadas. Em uma aplicação
multi-tenancy nós assumimos que os tenants tem um algo grau de configuração,
dependendo da definição dessas configurações, dois tenants pode possuir aparência e
workflows diferentes. Um argumento adicional para essa distinção é que o SLA(Service
Level Agreement) para cada tenant pode ser diferente (LIN, SUN, et al., 2009).
Outra abordagem que contrasta com multi-tenancy é a abordagem multiinstance. Com o aumento da popularidade de das tecnologias de virtualização e de cloud
Computing, multi-instance é a forma fácil de criar aplicações parecidas com multitenancy. É necessário apenas criar uma imagem de maquina virtual com a aplicação préconfigurada e, logo em seguida criar instâncias apartir dessa imagem. A abordagem
multi-instance é uma melhor abordagem quando o número de tenants for pequeno (JIE
GUO, SUN, et al., 2007).
6.3 Arquitetura Multi-tenancy
1
Nesse minicurso iremos tomar como base a arquitetura apresentada na Figura 6.2. Aqui
vemos que multi-tenancy afeta quase todas as camadas de uma aplicação típica, e como
tal, possui um grande potencial para se tornar um interesse transversal. Para manter o
impacto sobre o código (complexidade), as implementações de componentes multitenancy devem ser separadas da lógica dos tenants o tanto quanto possível. Caso
contrário, a manutenção pode se tornar um pesadelo, porque:
• Implementar código de requisitos da arquitetura multi-tenancy juntamente com
a lógica de negócio dos tenants em todas as camadas de aplicação, o que exige
que todos os desenvolvedores sejam reeducados sobre multi-tenancy;
• Misturar multi-tenancy com código de tenants leva ao aumento da
complexidade do código, pois é mais difícil manter o controle de onde o código
multi-tenancy é introduzido.
Estes dos problemas podem ser superados integrando cuidadosamente multi-tenancy na
arquitetura. No restante desta seção, descrevemos os componentes da arquitetura
130
abordada por Bezemer (BEZEMER e ZAIDMAN, 2010) para implementação de multitenancy como um interesse transversal.
A. Autenticação
Pelo motivo de uma aplicação multi-tenant ter apenas uma aplicação e instancia
de banco de dados, todos os tenants usam o mesmo ambiente físico. A fim de ser capaz
de oferecer customização do ambiente e ter certeza de que os tenants podem acessar
somente os seus próprios dados, tenants devem ser autenticados. Enquanto autenticação
de usuário é, possivelmente, já presente na aplicação de destino, um mecanismo
separado de autenticação de tenants específicos pode ser necessário, por duas razões: (1)
geralmente é muito mais fácil introduzir um mecanismo de autenticação adicional, do
que mudar um já existente, e (2) autenticação de tenants permite que um único usuário
faça parte de mais do que uma organização lógica, o que estende a idéia de autenticação
de usuários com “grupos”.
B. Configuração
Em uma aplicação multi-tenancy a customização deve ser possível através de
configuração. A fim de permitir que o usuário tenha uma experiência como se ele
estivesse trabalhando em um ambiente dedicado, é necessário permitir pelo menos os
tipos de configuração seguintes:
Estilo de Layout(Layout Style) – O componente de configuração de estilo de layout
permite o uso de temas e estilos específicos.
Configuração Geral (General Configuration) – O componente de configuração geral
permite a especificação de configurações específicas, como configurações de chave de
criptografia e detalhes do perfil pessoal.
Entrada e saída de arquivo (File I/O) – O componente de configuração de I/O de
arquivo permite a especificação de caminhos de arquivos, que podem ser usados para,
por exemplo, geração de relatório.
Fluxo de trabalho (Workflow) – O componente de configuração de fluxo de trabalho
permite a configuração de fluxos específicos. Por exemplo, configuração de fluxos é
necessária em uma aplicação de planejamento de recursos empresariais – ERP, em que o
fluxo de requisições pode variar significativamente para diferentes companhias.
C. Banco de dados (Database)
Em uma aplicação multi-tenancy há uma grande exigência para o isolamento dos dados.
Porque todos os tenants usam a mesma instância de um banco de dados é necessário ter
certeza de que eles podem acessar somente seus próprios dados. Atualmente sistemas
de gerenciamento de dados (Data Base Management Systems – DBMS) de prateleira
não são capazes de lidar com multi-tenancy, isso deve ser feito em uma camada entre a
131
camada lógica de negócios e o pool de banco de dados de aplicações. As principais
tarefas dessa camada são as seguintes:
Criação de novos tenants no banco de dados – Se a aplicação armazena ou recupera
dados que podem ser de tenants específicos, é tarefa da camada de banco de dados criar
os registros do banco de dados correspondente quando um novo tenant se inscreveu para
a aplicação.
Adaptação de consulta – A fim de prover um isolamento de dados adequado, a camada
de banco de dados deve ter certeza que consultas são ajustadas de forma que cada tenant
possa acessar somente seus próprios registros.
Balanço de carga – Para melhorar o desempenho de uma aplicação multi-tenancy é
necessário um balanceamento de carga eficiente para o pool de banco de dados. Note
que qualquer acordo feito no SLA de um tenant e quaisquer restrições impostas pela
legislação do país onde o tenant está localizado deve ser satisfeita. Além disso, a
aplicação pode ter requisitos de onde os dados de um tenant estão sendo armazenados,
por exemplo, para a geração de relatórios. Estes requisitos dificultam o uso de
algoritmos de balanceamento de carga existentes. Por outro lado, nossa expectativa é a
de que é possível criar algoritmos de balanceamento de carga mais eficientes usando as
informações que possuímos sobre os tenants.
Figura 6.2- Arquitetura Multi-tenancy (BEZEMER e ZAIDMAN, 2010)
132
6.4 Implementando um protótipo de aplicação multi-tenancy com Grails
.1
6.4.1 Introdução ao Framework Grails
.1
Para implementar um protótipo que demonstre a aplicabilidade da arquitetura multitenancy será utilizado o framework Grails. O Grails é um framework web open-source
que utiliza a linguagem Groovy, e outros frameworks consagrados como Hibernate,
Spring e Sitemesh, como mostrado na Figura 6.3. O Grails foi projetado para desenvolver
aplicações CRUD (Create, Read, Update e Delete) de forma simples e ágil, utilizando o
modelo de “escrever código por convenção” introduzido pelo Ruby on Rails. O Grails
está se propondo a trazer a produtividade do Ruby on Rails para a plataforma Java,
porém ele possui uma grande vantagem, sendo que a linguagem Groovy roda sobre uma
JVM, e pode utilizar classes Java e as diversas APIs que existem normalmente.
Groovy (padronizado pela JSR-241) é uma linguagem dinâmica e ágil para a
plataforma Java, que possui muitas características de linguagens de script como Ruby,
Python e Smalltalk, e ainda pode utilizar classes Java facilmente. Linguagens de script
estão ganhando cada vez mais popularidade, devido a quantidade reduzida de código
fonte necessário para implementar determinadas funcionalidades, se comparado com
uma implementação em Java.
Figura 6.3 - Arquitetura Grails
6.4.2 Instalando Grails
.1
Instalar o Grails framework pode ser considerada uma tarefa simples. O passo a passo
para a instalação do Grails framework é apresentado na Figura 6.4.
133
Uma vez instalado, é possível abrir um prompt de comando e testar sua instalação
utilizando, por exemplo, o comando “grails help”.
Figura 6.4 - Instalação Grails
Para criar uma aplicação em grails o desenvolvedor dever executar o comando:
grails create-app multitenantapp
Esse comando cria um projeto de aplicação grails contendo um conjunto de arquivos e
diretórios necessários para executar uma aplicação grails. Os diretórios criados e suas
descrições podem ser vistos com mais detalhes na Tabela 6.1.
Tabela 6.1 - Estrutura de pastas de uma aplicação Grails
Pasta
+ grails-app
+ conf
+ controllers
+ domain
+ i18n
Descrição
Contém as configurações da aplicação, como a
configuração de banco (DataSource.groovy) e onde
podem
ser
feitas
as
configurações
de
inicialização(BootStrap.groovy) entre outros.
Contém as classes de controller(controladores) da
aplicação.
Contém as classes de Domínio, ou modelos.
Contém arquivos inerentes a internacionalização.
134
+ services
+ taglib
+ views
+ layouts
+ grails-tests
+ lib
+ src
+ groovy
+ java
+ web-app
+ css
+ images
+ js
+ WEB-INF
+ index.jsp
Nessa pasta ficam as classes utilizadas na camada de
serviços do Grails, caso sejam criadas.
Contém as TagLibs criadas pelo usuário
Contém os arquivos “.gsp”(Groovy Server Pages)
utilizados para cada classe de domínio.
Nessa pasta ficam os templates da aplicação. Templates
em Grails são views incluídas em outras views.
Parta que contém os testes unitários
Contém as libs externas, como por exemplo os drivers de
conexão aos bancos de dados
Contém classes groovy que não se encaixam nem em
Domain, Controller ou Service.
Contém classes java que poderão ser usadas na aplicação
Contém os arquivos .css
Imagens
JavaScript
Arquivos relacionados ao deploy
O Index da app
Para executar a aplicação criada deverão ser executados os seguintes comandos:
>> cd multitenantapp
>> grails run-app
O comando “cd multitenantapp” irá abrir o diretório da aplicação e o comando “grails
run-app” executará a aplicação.
Para adicionar um cadastro de uma entidade (CRUD) à aplicação, deve ser criado uma
classe de domínio e em seguida uma classe de controller que irá gerenciar as requisições
para o cadastro desta entidade.
>> grails create-domain-class Product
>> grails create-controller multitenantapp Product
O primeiro comando cria uma classe de domínio no seguinte endereço
>> grails create-domain-class Product
“..\multitenantapp\grails-app\domain\multitenantapp\Product.groovy”.
Esse arquivo
>>
grails
create-controller
multitenantapp
Product
deverá ser alterado para o código da Figura 6.5 a seguir:
135
Figura 6.5 - código Product.groovy
O segundo comando cria a classe de controller, que deverá ser alterada para o código a
da seguir:
Figura 6.6 - Código da Classe Controller
Uma vez criadas as classes de domínio e controller,o comando “grails run-app” deverá
ser executado novamente. Após isso será possível acessar o link
“http://localhost:8080/multitenantapp” para visualizar a primeira tela da aplicação,
mostrado na Figura 6.7, com o CRUD da entidade criada (Product).
Figura 6.7 - Tela Inicial de uma aplicação Grails
Assim, observamos que com poucos comandos temos uma pequena aplicação grails
funcionando.
6.4.3. Componentes de uma aplicação multi-tenancy
.1
Para implementar uma aplicação multi-tenancy é necessário implementar autenticação,
controle de configurabilidade e controle de acesso a dados que atendam às necessidades
de uma aplicação multi-tenancy que foram descritos nos tópicos anteriores. A fim de
diminuir a complexidade da aplicação de exemplo não será implementado o controle de
configurabilidade em nosso aplicativo de demonstração.
136
Grails disponibiliza uma arquitetura de plugins que promove o reuso e o aumento de
produtividade. Dentre os plug-ins disponíveis existem plugins que facilitam muito a
implementação de aplicações multi-tenancy em Grails. São eles Multi-tenant Plugin
(Core) e Multi-tenant Spring Security Integration. Esses 2 plugins extendem as
funcionalidades de controle de acesso a dados e autenticação de forma a atender os
requisitos de aplicações multi-tenant.
Para dar continuidade ao nosso exemplo prático será instalado agora um plugin que
adiciona a funcionalidade de autenticação em nossa aplicação. Para isso é necessário a
execução dos comandos a seguir.
>> grails install-plugin spring-security-core 1.1.2
>> s2-quickstart login SecUser Role Requestmap
Para que esse plugin funcione é necessário que o código no arquivo BootStrap.groovy
existente na pasta “conf” do seu projeto esteja semelhante ao código apresentado na
Figura 6.8. Em Seguida já é possível re-executar a aplicação com o comando “run-app” e
verificar que para utilizar a aplicação agora é necessário utilizar um login e senha. As
configurações adicionadas no arquivo BootStrap.groovy criaram no banco de dados 2
usuários(user1 e user2), ambos com senha “123”.
Figura 6.8 - BootStrap.groovy (Single Tenant)
O próximo passo é instalar os plug-ins necessários para tornar nosso exemplo uma
aplicação multi-tenant. Para isso é necessário a execução do comando a seguir em nosso
projeto.
>> grails install-plugin multi-tenant-spring-security
Após a instalação do plugin são necessárias algumas configurações adicionais:
137
1. Adicionar o campo “Integer userTenantId” na classe SecUser.groovy. Isso fará
com que cada usuário esteja associado a um tenant específico. Ao cadastrar um
usuário, ele deverá possuir um valor para o campo userTenantId, isso irá indicar
quais registros do banco de dados ele terá acesso.
2. Anotar a classe Product.groovy com “@MultiTenant”. Em uma aplicação multitenancy poderemos ter entidades que terão ou não características multi-tenancy.
Ou seja, mesmo em uma aplicação multi-tenancy poderemos ter entidades que
terão seus registros compartilhados entre todos os tenants. Para indicar quais
entidades terão seus registros filtrados por tenant utilizamos a anotação
@MultiTenant.
3. Adicionar no bloco de constraints da classe Product.groovy a seguinte linha de
código “tenantId(display:false)”. Isso fará com que o campo tenantId, que é
criado dinamicamente não seja alterado pelos usuários. Dado que o
gerenciamento de seu valor é feito pelo plugin.
4. Altera a classe BootStrap.groovy para que o valor do atributo userTenantId seja
informado na criação dos 2 usuários padrões do sistema. O código da classe
BootStrap.groovy deverá ficar semelhante ao código apresentado na Figura 6.9.
Essa alteração fará com que cada usuário padrão do sistema esteja em um tenant
diferente.
5. Adicionar o código da Figura 6.10 ao final do arquivo Config.groovy, localizado
na pasta “conf” do projeto.
Figura 6.9 - BootStrap.groovy (Multi-tenant)
Figura 6.10 - Alteração Config.groovy
138
Seguido estes passos, as funcionalidades básicas de uma aplicação multi-tenancy estão
presentes no nosso exemplo. Para validar o funcionamento é necessário efetuar o login
com o usuário user1(senha=123) e cadastrar alguns produtos. Em seguida efetuar login
com o usuário user2 e, também, efetuar alguns cadastros no sistema. Será possível ver
que os dados cadastrados efetuados pelo usuário user1 não serão visualizados pelo
usuário user2, e vice versa. Isto ocorre porque quando esses usuários foram criados
colocados em tenants diferentes.
6.5. Conclusão
.1
Tomando como base a fundamentação teórica e o exemplo prático apresentado,
concluímos que é possível implementar uma aplicação multi-tenancy de forma produtiva
e com alto grau de reuso de código. Apesar do exemplo prático ser implementado em
Groovy e Grails, essa arquitetura pode ser replicada em várias outras linguagens
existentes no mercado. Embora os esforços de pesquisa na área de SaaS e multi-tenancy
estejam crescendo bastante ainda existem vários pontos a serem explorados e evoluídos,
como avaliação de desempenho, monitoramento de tenants, escalabilidade, migração de
aplicações legadas para a arquitetura multi-tenancy, entre outros.
6.6. Referências
.1
ABDUL-JAWAD,. Groovy and Grails Recipes. Berkely: Apress, 2009.
BEZEMER, C.-P.; ZAIDMAN, A. Multi-tenant SaaS applications: maintenance dream
or nightmare? ERCIM Workshop on Software Evolution (EVOL) and International
Workshop on Principles of Software Evolution (IWPSE), New York, 2010.
CHONG , ; CARRARO,. Architecture Strategies for Catching the Long Tail, 2006.
Disponivel em: <http://msdn.microsoft.com/en-us/library/aa479069.aspx>. Acesso em:
2011 out. 01.
HU WANG, Z. et al. A Study and Performance Evaluation of the Multi-Tenant Data
Tier Design Patterns for Service Oriented Computing. ICEBE '08 Proceedings of the
2008 IEEE International Conference on e-Business Engineering, Washington, DC,
2008. 94-101.
JANSEN, S.; HOUBEN, G.-J.; BRINKKEMPER, S. Customization realization in
multi-tenant web applications: case studies from the library sector. Proceeding
ICWE'10 Proceedings of the 10th international conference on Web engineering,
Berlin, Heidelberg, 2010. 445-459.
JIE GUO, et al. A Framework for Native Multi-Tenancy Application Development and
Management. 9th IEEE International Conference on E-Commerce Technology and
the 4th IEEE International Conference on Enterprise Computing, E-Commerce,
and E-Services, Tokyo, 2007. 551 - 558.
KLEIN, D. Grails: A Quick-Start Guide. [S.l.]: Pragmatic Bookshelf, 2009.
KWOK, T.; NGUYEN, T.; LAM, L. A Software as a Service with Multi-tenancy
Support for an Electronic Contract Management Application. International
Conference on Services Computing. Washington: IEEE Computer Society. 2008. p.
179-186.
139
LIN, H. et al. Feedback-Control-Based Performance Regulation for Multi-Tenant
Applications. 15th International Conference on Parallel and Distributed Systems
(ICPADS). Shenzhen: IEEE. 2009. p. 134 - 141.
MELL , P.; GRANCE,. Draft nist working definition of cloud computing - v15.
National Insitute of Standards and Technology, 2009. Disponivel em:
<http://www.nist.gov/itl/cloud/upload/cloud-def-v15.pdf>. Acesso em: 1 out. 2011.
NITU. Configurability in SaaS (software as a service) applications. Proceedings of the
2nd annual India Software Engineering Conference (ISEC), Pune, India, 2009. 1926.
ROCHER, G. K. The Definitive Guide to Grails. Berkely: Apress, 2006.
SALESFORCE, 2000. Disponivel em: <http://www.salesforce.com>. Acesso em: 2011
out. 1.
SMITH, G.; LEDBROOK, P. Grails in Action. Greenwich: Manning Publications,
2009.
TAURION, C. Cloud Computing: Computação em Nuvem: Transformando o mundo
da tecnologia da informação. Rio de Janeiro: Brasport, 2009.
WARFIELD, B. Multitenancy Can Have a 16:1 Cost Advantage Over Single-Tenant.
SmoothSpan
Blog,
2007.
Disponivel
em:
<http://smoothspan.wordpress.com/2007/10/28/multitenancy-can-have-a-161-costadvantage-over-single-tenant/>. Acesso em: 17 out. 2011.
140
Capítulo
7
Introducão a Agentes Autônomos e Sistemas Multiagentes
1
Samy Sá1, João Alcântara1
Departamento de Computação – Universidade Federal do Ceará (UFC)
Caixa Postal 12.166 – 60.455-970 – Fortaleza – CE – Brazil
{samy,jnando}@lia.ufc.br
Abstract. The goal of this chapter is to introduce the main concepts in the area
of autonomous agents and multiagent systems. Starting with the question "What
is an agent?", we discuss the key aspects of building agents and agent
societies. For each such concept, we provide some intuition about it, its
formalization, illustrations and examples. In the beginning, we consider the
properties of a single agent and its relation towards the environment in which it
exists. Next, we step up to observe agents societies and the peculiarities that
emerge from the plurality of autonomous self-interested entities. In such
situations, it is possible that agents get involved in situations of conflict or
cooperation, or that some coordination of their actions is required to assure their
goals can be achieved.
Resumo. O objetivo deste capítulo é introduzir os principais conceitos da área
de agentes autônomos e sistemas multiagentes. Começando pela pergunta "O
que é um agente?", abordamos os aspectos-chave para a contrução de
agentes autônomos e sociedades de agentes. Para cada conceito abordado,
fornecemos uma intuição sobre o mesmo, sua formalização, ilustrações e
exemplos. Inicialmente, consideramos as propriedades de um único agente e
sua relação com o ambiente em que existe. Em seguida, passamos a observar
sociedades de agentes e as peculiaridades emergentes da pluralidade de
entidades autônomas dotadas de interesses próprios. Em tais situações, é
possível que os agentes se envolvam em situações de disputa ou cooperação,
ou que precisem coordenar suas ações para garantir que seus objetivos
possam ser cumpridos.
7.1. O que são agentes?
Nesta seção, vamos definir o que são agentes e abordar alguns aspectos sobre como
construí-los. No entanto, devemos destacar que a definição de agente é controversa,
pois depende muito do domínio do problema a ser explorado. Apesar disso, todos nós
iremos concordar que uma característica central que todo agente deve ter é o da
autonomia. Mas o que vem a ser essa autonomia? Responder essa pergunta não é
fácil e irá depender mais uma vez do tipo de problema que estamos lidando. Para
alguns problemas, autonomia pode ser entendida como a capacidade de aprender a
partir da própria experiência; já em outras aplicações, aprendizagem é um aspecto a
ser evitado. Começaremos, então, com uma definição de agentes adaptada de
[Wooldridge and Jennings 1995]:
Um agente é um sistema computacional que está situado em algum ambiente e
é capaz de ações autonômas nesse ambiente com o propósito de alcançar os
objetivos que lhe foram delegados. O que precisamos comprender é que agentes
devem decidir por conta própria o que precisa ser feito para alcançar os objetivos
propostos em vez de receber comandos para tal fim. Em suma, um agente deve ser
141
não só capaz de tomar decisões, mas também de escolher que ações tomar e quando
executá-las.
Figura 7.1. Um agente em seu ambiente
Como ilustrado na Figura 7.1, um agente percebe o ambiente no qual ele está
inserido através de sensores. Como resultado dessa percepção, o agente produz
como saída uma ação que irá, por sua vez, alterar o ambiente. Esse processo de
percepção/ação continua ciclicamente e é a base do funcionamento de um agente.
Não obstante, na maioria dos problemas de interesse prático, um agente irá possuir
um controle parcial sobre o ambiente. Isso quer dizer que a mesma ação executada
duas vezes em circunstâncias aparentemente idênticas podem ocasionar resultados
completamente diferentes, podendo, em particular, falhar na obtenção dos resultados
esperados. Podemos, assim, dizer que os ambientes em geral são nãodeterminísticos.
No presente contexto, devemos compreender autonomia como a habilidade de
decidir como agir para alcançar os objetivos delegados. Mas até que ponto um agente
é autônomo? Um agente, por exemplo, não deve ter autonomia para escolher o
objetivo a ser alcançado pelo sistema; sua autonomia limita-se, portanto, a buscar os
meios para alcançar esse objetivo. Além disso, nem todo agente possui o mesmo nível
de autonomia. Por exemplo, um agente participante de uma operação médica não
deve ter a mesma autonomia de um agente responsável por desligar os quartos de um
hotel quando não houver ninguém presente.
Mais recentemente, tem-se recorrido à ideia de agentes com a autonomia
ajustável de acordo com as circunstâncias. O princípio geral é que um agente deve
entregar o poder de tomar decisão para uma autoridade maior (um ser humano)
quando
 Ele acredita que isso trará grandes benefícios;
 Ambiente com alto grau de incerteza;
 A decisão pode causar danos;
 Incapacidade do agente de tomar decisão.
7.1.1. Agentes Inteligentes
Com base no que foi exposto, podemos perceber que a noção de agente é bastante
abrangente e vai de um simples interruptor de luz ou um termostato ao complexo
sistema de controle de uma nave espacial não-tripulada. No entanto, nem todos esses
agentes (como é o caso do termostato) são inteligentes. Mas o que seria um agente
inteligente? De acordo com [Wooldridge and Jennings 1995], um agente é inteligente
se ele possui
• Reatividade
142
• Proatividade
• Habilidade Social
7.1.1.1. Reatividade
Agentes inteligentes devem perceber seu ambiente e responder atempadamente às mudanças ocorridas nele para satisfazer os seus objetivos. Agora se as únicas mudanças que
ocorrem no ambiente são resultantes das ações do agente, ele não precisará se preocupar com essas mudanças, pois as terá sobre controle. Não obstante, o mundo não é bem
assim: os ambientes são normalmente dinâmicos e as mudanças ocorrem independentes do agente, dificultando sobremaneira o desenvolvimento de sistemas computacionais
eficientes. Podemos definir um sistema reativo como aquele que mantém uma interação
contínua com o seu ambiente e responde em tempo hábil às mudanças que ocorrem nele.
7.1.1.2. Proatividade
Desenvolver agentes reativos é considerado relativamente simples na medida que para
cada estímulo percebido do ambiente, haja uma regra que permita ao agente dar a resposta
mais adequada. Em geral, no entanto, nós queremos que os agentes executem tarefas para
nós. Com isso, agentes inteligentes devem também ser proativos, ou seja, devem exibir
um comportamento orientado a objetivos, tomar a iniciativa para alcançá-los além de
reconhecer novas oportunidades.
7.1.1.3. Habilidade Social
O mundo real é um mundo com multiagentes; em pouquíssimas tarefas, podemos alcançar
algum êxito sem a ajuda de outros. O problema é que nem todo mundo compartilha os
nossos mesmos objetivos, sendo muita vezes necessário negociar e cooperar com outros.
Algo similar ocorre num ambiente computacional. Nesse sentido, a habilidade social de
um agente deve ser compreendida como a sua capacidade de interagir com outros agentes
(e possivelmente humanos) através de alguma linguagem de comunicação de agentes.
Através dessa linguagem os agentes podem
Cooperar: neste caso, os agentes trabalham como se estivessem num time com o objetivo de alcançar um objetivo em comum. Os agentes cooperam quando um agente
sozinho não é capaz de alcançar o objetivo ou quando o trabalho conjunto irá
produz um resultado melhor .
Coordenar: nem sempre dois ou mais agentes podem usar o mesmo recurso ao mesmo
tempo. Assim é preciso que eles coordenem suas atividades de modo que os agentes envolvidos possam fazer uso do recurso.
Negociar: é a habilidade de fazer acordos sobre assuntos de interesse em comum. Se
você quer assistir TV e seu irmão quer estudar, um possível acordo é você ligue a
TV, mas com volume baixo. Tipicamente, negociação envolve proposta e contraproposta com compromissos feitos pelos participantes.
Essas habilidades sociais serão esmiuçadas mais adiante.
143
7.1.1.4. Algumas Propriedades que Agentes Podem Ter
Além das propriedades citadas um agente (inteligente) pode ter
• Mobilidade: habilidade do agente se mover. Para um agente software, esse movimento é por volta de uma rede eletrônica;
• Veracidade: se um agente irá propositalmente comunicar informação falsa para
alcançar seu objetivo;
• Benevolência: se agentes possuem objetivos conflitantes e se nesse caso, eles vão
se ajudar entre si;
• Racionalidade: se um agente irá agir para alcançar seus objetivos e não irá deliberadamente agir para evitar esse alcance;
• Aprendizagem/adaptação: se os agentes melhoram o seu desempenho com o decorrer do tempo.
7.1.2. Arquitetura Abstrata para Agentes
Vamos agora formalizar a noção de agente da qual temos discutido. Primeiramente, iremos caracterizar o ambiente simplesmente como um conjunto finito, discreto E de estados
instantâneos:
E = {e, e′ , . . .} .
Os agentes possuem um repertório de ações disponíveis, que podem ser usadas
para transformar o estado do ambiente. Seja
Ac = {a, a′ , . . .}
o conjunto (finito) dessas ações.
A ideia geral é que o ambiente começa em algum estado e0 ∈ E. Então o agente
inicia escolhendo uma ação α0 ∈ Ac. Como resultado dessa ação, o ambiente poderá
escolher (inclusive não-deterministicamente) dentre um certo número de estados possíveis
aquele que servirá de resposta para o agente (chamemo-lo de e1 ). Com base nesse estado
e1 , o agente terá que escolher uma ação para executar, que irá, por sua vez, provocar uma
resposta do ambiente e assim por diante. Uma execução r de um agente em um ambiente
é, portanto, uma sequência alternada de estados do ambiente e ações:
α0
α1
α2
α3
αu−1
r ∶ e0 → e1 → e2 → e3 → ⋯ → eu .
Sejam
• R o conjunto de todas as sequências finitas possíveis (sobre E e Ac);
• RAc o subconjunto dessas sequências que terminam em ação;
• RE o subconjunto dessas sequências que terminam em um estado.
Nós usaremos r, r′ , . . . para nos referirmos aos membros de R. Para representar
o efeito que as ações do agente acarretam no ambiente, nós introduzimos a função de
transformação de estados:
τ ∶ RAc → 2E .
144
Observe que a função de transformação de estados recebe uma execução terminando em uma ação α do agente e retorna um conjunto de possíveis estados que poderiam
servir de respostas a α. Essa definição deixa claro que o ambiente é dependente do seu
histórico, ou seja, o próximo estado do ambiente não é somente determinado pela última
ação do agente e pelo estado corrente, mas por tudo que ocorreu antes. O segundo aspecto
a destacar é que essa definição permite a definição de ambientes não-determinísticos.
Quando τ (r) = ∅, temos que a execução r terminou. Vamos assumir em nosso
sistema que todas as execuções chegam a um fim em algum momento.
Formalmente, um ambiente é uma tripla Env = ⟨E, e0 , T ⟩, em que E é um conjunto de estados, e0 ∈ E é um estado inicial e τ é uma função transformadora de estados.
Nós podemos agora formalizar a noção de agente como sendo a função
Ag ∶ RE → Ac
Um agente, portanto, toma decisoes sobre que ação executar com base no histórico
do sistema até aquele momento. Chamemos de AG o conjunto de todos os agentes.
Nós definimos um sistema como um par contendo um agente e um ambiente;
todo sistema será associado com um conjunto de execuções possíveis. Nós denotamos o
conjunto de todas as execuções de Ag em um ambiente Env por R(Ag, Env ). Por simplicidade, R(Ag, Env ) conterá apenas execuções r que terminam (τ (r) = ∅). Formalmente,
uma sequência
(e0 , α0 , e1 , α1 , e2 , . . .)
representa uma execução de um agente Ag num ambiente Env = ⟨E, e0 , τ ⟩ se
1. e0 é o estado inicial de Env
2. α0 = Ag(e0 ) e
3. para u > 0
eu ∈ τ ((e0 , α0 , . . . , αu−1 )) e αu = Ag((e0 , α0 , . . . , eu )).
Dois agentes Ag 1 e Ag 2 possuem comportamentos equivalentes com relação a um
ambiente Env se R(Ag 1 , Env ) = R(Ag 2 , Env ).
Alguns agentes são puramente reativos, isto é, decidem com base exclusivamente
no presente e não levam conta o seu histórico:
Ag ∶ Env ← Ac.
O termostato é um exemplo de agente reativo, podendo ser definido como
Ag(e) = {
desligado se e = temperatura ok
ligado
caso contrário
Nós precisamos agora refinar nosso modelo de agente e separar a decisão de um
agente em dois subsistemas: percepção e ação. Ademais, os agentes têm alguma estrutura
de dados interna que permita registrar a informação sobre os estados e o histórico (veja
Figura 7.2).
145
Figura 7.2. Um agente com estado
Nessa arquitetura, a função veja tem como objetivo representar a habilidade do
agente de capturar o seu ambiente. No mundo real, essa função é implementada em
hardware como um sensor ou uma câmera de vídeo por exemplo. Matematicamente,
podemos definí-la como
veja ∶ E → Per ,
em que Per é um conjunto de percepções. Já a função ação representa o processo de
tomada de decisão do agente. Essa função vai receber como entrada o estado interno em
que o agente se encontra e retornar a ação a ser tomada:
ação ∶ I → Ac,
em que I é o conjunto de todos os estados internos do agente. A atualização do estado interno do agente é feita pela função próximo a partir do estado atual e das novas percepções
obtidas pelo agente:
próximo ∶ I × Per → I.
O comportamento de um agente baseado em estados pode ser sumarizado como segue:
1. Agente Ag começa em algum estado interno i0 .
2. Ag observa o estado do seu ambiente e e gera uma percepção veja(e).
3. O estado interno de Ag é atualizado via função próximo e passa a ser
próximo(i0 , veja(e)).
4. A ação selecionada por Ag é ação(próximo(i0 , veja(e))). Essa ação é então executada.
5. Vá para (2).
7.1.3. Abordagens para a Construção de Agentes
Na sequência, iremos mostrar as principais abordagens desenvolvidas para a construção
de agentes: agentes como provadores de teorema, programação orientada a agentes, agentes reativos e agentes híbridos.
146
7.1.3.1. Um Agente como um Provador de Teoremas
Na abordagem tradicional de Inteligência Artificial, IA simbólica, o comportamento inteligente é gerado em um sistema através de uma representação simbólica do seu ambiente e
do comportamento desejado. Partindo desse pressuposto e recorrendo às fórmulas lógicas
para fazer essa representação, em [Genesereth and Nilsson 1987] os autores desenvolveram um modelo simples de agente baseado em lógica. Em tais agentes, o estado interno é
assumido ser um banco de dados de fórmulas da Lógica Clássica de Primeira Ordem. A
ideia básica é usar lógica para codificar uma teoria retratando a melhor ação a ser executada numa dada situação.
Assim sendo, sejam L um conjunto de sentenças da Lógica Clássica de Primeira
Ordem, D = 2L , o conjunto dos conjuntos de fórmulas de L. O estado interno de um
agente é, então, um elemento de D. Nós escrevemos ∆, ∆1 , . . . para membros de D.
O processo de tomada de decisão de um agente é modelado através de um conjunto de
regras de dedução ρ. Essas são regras simples de inferência para a lógica. Nós escrevemos
∆ ⊢ρ φ se a fórmula φ pode ser provada do banco de dados ∆ usando somente regras de
dedução ρ. A função de percepção do agente veja permanece a mesma:
veja ∶ S → Per
Similarmente, a função próximo tem a forma
próximo ∶ D × Per → D
Essa função próximo mapeia, portanto, um banco de dados e uma percepção em
um novo banco de dados. No entanto, a função de seleção de novas ações
ação ∶ D → Ac
é definida em termo de suas regras de dedução. O pseudo-código dessa função é dado
pelo algoritmo abaixo:
Algorithm 1 Ação(∆ ∶ D) retorna uma ação Ac
1: begin
2: for cada α ∈ Ac do
3:
if ∆ ⊢ρ Faça(α) then
4:
return α
5:
end if
6: end for
7: for cada α ∈ Ac do
8:
if ∆ ⊢
/ ρ ¬Faça(α) then
9:
return α
10:
end if
11: end for
12: return null
13: end
147
A ideia é que o programador do agente irá codificar as regras de dedução ρ e
um banco de dados ∆ de um modo tal que se uma fórmula Faça(α) possa ser derivada,
em que α é um termo que denota uma ação, então α é a melhor ação a ser executada.
Nesta abordagem, o processo de tomada de decisão é visto como uma dedução, sendo
esse processo codificado como uma teoria lógica e a parte de selecionar uma ação reduzse a um problema de prova. Essa abordagem é elegante e possui uma semântica bem
definida. Não obstante, problemas relacionados a sua alta complexidade computacional
tornam questionáveis se agentes como provadores de teorema podem ser empregados em
ambientes que requerem decisões rápidas. Além disso, eles partem do pressuposto que o
mundo não irá mudar de modo significativo enquanto o agente está decidindo o que fazer.
Quando isso não se aplica, essa abordagem poderá acarretar em resultados indesejáveis.
7.1.3.2. Programação Orientada a Agentes
Em 1990, Yoav Shoham introduziu um novo paradigma de programação baseado numa
visão societária da computação. Chamado de "programação orientada a agentes", sua
principal ideia é permitir programar agentes diretamente em termos noções como crença,
compromisso e intenção. A primeira implementação desse paradigma foi a linguagem de
programação Agent0. Nessa linguagem, um agente é especificado como um conjunto de
capacidades (coisas que ele pode fazer), um conjunto de crenças iniciais, um conjunto de
compromissos iniciais e um conjunto de regras de compromisso. O componente-chave
que determina como o agente agente vai agir é o conjunto de regras de compromissos.
Cada regra de compromisso contém uma condição de mensagem, uma condição mental
e uma ação. Para determinar se uma regra pode ser aplicada, a condição de mensagem
é confrontada com as mensagens que o agente recebeu; a condição mental é confrontada com as crenças do agente. Se essas condições forem satisfeitas, o agente torna-se
comprometido àquela ação.
Ações em Agent0 podem ser privadas, correspondendo a uma sub-routina executada internamente ou comunicativa (envio de mensagens). Por sua vez, mensagens são
restritas a três tipos: ‘requests’ or ‘unrequests’ para respectivamente se comprometer a
ou declinar a execução de ações e mensagens do tipo ‘inform’. É de se destacar que mensagens request e unrequest resultam tipicamente na modificação dos compromissos do
agente, enquanto que mensagens inform alteram as crenças do agente. A seguir, mostramos um exemplo de regra de compromisso em Agent0:
COMMIT(
( agent, REQUEST, DO(time, action)
), ;;; msg condition
( B,
[now, Friend agent] AND
CAN(self, action) AND
NOT [time, CMT(self, anyaction)]
), ;;; mental condition
self,
DO(time, action)
)
148
Essa regra pode ser parafraseada da seguinte maneira: se eu recebo uma mensagem de agent que me solicita executar action em time e eu acredito que
• agent é um amigo no momento atual;
• eu posso fazer essa ação;
• em time, eu não estou comprometido em fazer qualquer outra ação,
então eu me comprometo a fazer action em time.
7.1.3.3. Agentes Reativos
Dois problemas principais são verificados com as abordagens baseadas em representação
lógica/simbólica dos agentes:
Problema da Transdução: como traduzir o mundo real numa representação simbólica?
Problema da Representação/Raciocínio: como representar simbolicamente informação sobre complexas entidades do mundo real e raciocinar com elas eficientemente?
As dificuldades de lidar com esses problemas nas abordagens simbólicas levaram
muitos pesquisadores a investigar alternativas. Uma delas é a abordagem reativa, que
tem esse nome porque tais sistemas são frequentemente percebidos como simplesmente
reagindo a um ambiente sem raciocinar sobre ele. Um dos pesquisadores que estudou
essa abordagem, Rodney Brooks, argumentou o seguinte:
1. Comportamento inteligente pode ser gerado sem representação explícita do tipo
que a IA simbólica propõe.
2. Comportamento inteligente pode ser gerado sem raciocínio abstrato explícito do
tipo que a IA simbólica propõe.
3. Inteligência é uma propriedade emergente de certos sistemas complexos.
Ele identifca duas ideias centrais em sistemas reativos:
1. Situado e encorpado: inteligência real é situada no mundo; não são sistemas
desencorpados tais como provadores de teorema ou sistemas especialistas.
2. Inteligência e emergência: comportamento inteligente surge como um resultado
da interação de um agente com o seu ambiente. Ademais, inteligência está no olho
do observador; não é uma propriedade inata e isolada.
Para ilustrar suas ideias, Brooks construiu alguns agentes baseados em sua arquitetura da
subsunção. Nesse trabalho, podemos identificar que no processo de tomada de decisão do
agente é feito através de um conjunto de comportamentos de realização de tarefas. Cada
comportamento pode ser visto como uma simples regra situação → ação, que mapeia
uma entrada de dados (perceptual) diretamente em ações. Além do mais, cada comportamento ‘compete’ com outros pelo controle sobre o agente. Uma outra característica dessa
abordagem é que ela está dividida em camadas que formam uma hierarquia, sendo que
as camadas inferiores representam tipos mais primitivos de comportamentos (tais como
evitar obstáculos) e têm precedência sobre camadas superiores dessa hierarquia (Figura
7.3).
149
Figura 7.3. Exemplo de máquina baseada em arquitetura da subsunção
É válido mencionar que uma das vantagens desses sistemas baseados em arquitetura da subsunção é a sua simplicidade aliada à sua eficiência computacional, sendo
empregado em situações que exigem um rápido tempo de resposta. Em [Steels 1990], por
exemplo, o autor propõe um agente baseado em arquitetura da subsunção concebido para
explorar planetas distantes.
7.1.3.4. Agentes Híbridos
Muitos pesquisadores têm argumentado que tanto uma abordagem que seja completamente deliberativa quanto um que seja completamente reativa não são apropriadas para a
construção de agentes. Em função disso, eles sugeriram um sistema híbrido que buscasse
tirar proveito das boas qualidades de ambas as abordagens. Um caminho direto para tal
sistema seria o de construir um agente a partir de dois (ou mais) subsistemas:
• Subsistema Deliberativo: contém um modelo simbólico do mundo que desenvolve planos e toma decisões à maneira proposta pela IA Simbólica;
• Subsistema Reativo: é capaz de reagir a eventos sem ter que fazer raciocínios
complexos.
De um modo geral, o componente reativo tem precedência sobre a parte deliberativa. Pode-se ainda argumentar que essa forma de estruturação leva naturalmente à ideia
de arquitetura em camadas, das quis TouringMachines [Ferguson 1992] and InteRRaP
[Müller and Pischel 1993] são dois bem conhecidos exemplos. Em tais arquiteturas, os
subsistemas de controle de um agente são dispostos numa hierarquia com as camadas
mais altas lidando com informação cada vez mais abstrata.
Um problema central nessas arquiteturas é que tipo de estrutura de controle embutir nos subsistemas do agente para gerir as interações entre as várias camadas. Em todo
caso, podemos identificar dois tipos de fluxo de controle nessas arquiteturas por camadas:
• Camada horizontal: cada camada está diretamente conectada às entradas sensoriais e as ações retornadas como saídas (Figura 7.4(a)). Note que é como se cada
camada agisse como um agente, produzindo sugestões sobre que ação executar.
• Camada vertical: nesse tipo de arquitetura entradas sensoriais e as ações como
saída são lidadas cada uma por no máximo uma camada (Figuras 7.4(b) e (c)).
150
Figura 7.4. Agentes Híbridos
7.2. Sistemas Multiagentes
Até o momento temo-nos concentrado na construção de um agente. No entanto, à exceção de sistemas extremamente triviais, não iremos encontrar um sistema com um único
agente. A razão é que um sistema contém um número de subsistemas que devem interagir uns com os outros com o objetivo de executar suas tarefas com êxito. O ponto-chave
agora não é como construir um agente, mas como construir uma sociedade de agentes. A
Figura 7.5 ilustra a estrutura típica de um Sistema Multiagente.
Figura 7.5. Estrutura típica de um Sistema Multiagente
Um aspecto fundamental aqui é a interação entre agentes. Num sistema multiagentes, os agentes são capazes de agir num ambiente; diferentes agentes têm diferentes
esferas de influência, ou seja, as partes do ambiente sobre a qual os agentes vão ter alguma forma de controle. Esferas de influência com áreas em comum dão margem para
151
uma relação de dependência entre os agentes. Por exemplo, dois agentes robôs podem ser
capazes de passar por uma porta, mas ambos não poderão fazer isso simultanemente.
Num sistema multiagente, iremos encontrar duas maneiras distintas (muitas vezes
conflitantes) de se analisar um agente:
• Na perspectiva de quem construiu um agente individual, espera-se que esse agente
faça o melhor para ele.
• Na perspectiva de quem projetou o sistema multiagente, o sistema deve otimizar
o desempenho do sistema como um todo.
Um bom sistema multiagente é aquele que consegue satisfazer essas duas perspectivas e evitar conflitos. Ademais, no que tange aos tipos de interações que podem ocorrer
entre os agentes, podemos destacar:
Coordenação : objetivo é que um agente pelo menos não interfira no trabalho do outro.
Eles podem, inclusive, coordenarem entre si para que um agente possa ajudar um
outro.
Comunicação : coordenação normalmente requer comunicação entre os agentes.
Cooperação : Dependendo do objetivo de cada agente, quando um agente coordena ele
pode também querer cooperar ou ainda competir.
Negociação : se um agente age por interesse próprio, então cooperação é descartada, mas
agentes podem recorrer a uma negociação para alcançar cooperação.
Em suma, um sistema multiagente consiste de um número de agentes que interagem entre si. No caso mais geral, eles vão agir para atender os propósitos para os quais
foram projetados, podendo ter diferentes objetivos e motivações. Não obstante, para que
essa interação seja exitosa, eles terão que cooperar, coordenar e negociar uns com os
outros [Wooldridge 2009].
7.3. Interações entre Agentes
Como sugerido anteriormente na Figura 7.5, as esferas de influência dos agentes em um
sistema podem coincidir. Quando isso acontece, abre-se espaço para conflitos, mas também para ganhos mútuos. De certa maneira, o que faz um sistema multiagentes são o
conjunto de entidades autônomas (às quais chamamos de agentes) e as interações entre as
mesmas. Portanto, compreender que tipo de interações se dão entre os agentes e em que
situações elas ocorrem é de extrema importância ao nos depararmos com algo que pareça
um domínio multiagentes.
7.3.1. Utilidades e Preferências
Para simplificar o entendimento dos conceitos a seguir, vamos nos restringir a sistemas
com apenas dois agentes, os quais chamaremos de i e j, respectivamente. Assumimos que
cada um desses agentes tem interesses próprios (é self-interested), ou seja, cada agente
tem suas próprias preferências e desejos sobre como o mundo deveria ser. No momento,
também não vamos nos preocupar com a origem desses desejos e preferências. Considere
Ω = {ω1 , ω2 , . . . , }, o conjunto de todos os possíveis estados ou resultados (outcomes)
sobre os quais os agentes têm preferências.
As preferências dos agentes são capturadas por funções de utilidade, uma para
cada agente, que designam um número real para cada resultado em Ω. Esse número real
152
indica o quão favorável o agente acredita que esse resultado lhe é, de forma que, quanto
maior o número, mais o agente tem interesse naquele estado. Dessa forma, a função de
utilidade do agente i será
ui ∶ Ω → R
e as preferências do agente j são capturadas pela função de utilidade
uj ∶ Ω → R.
Note que, para cada agente, a relação ρ = {(ω, ω ′ ) ∈ Ω × Ω ∣ ui (ω) ≥ ui (ω ′ )} é
uma ordem parcial, isto é, uma relação reflexiva, transitiva e anti-simétrica.
7.3.2. Encontros entre Agentes
Vamos agora considerar um modelo para o ambiente no qual os agentes agem. Consideraremos que os agentes escolhem simultaneamente que ação irão executar no ambiente
e que um dos estados de Ω será o resultado dessas escolhas. O resultado dependerá de
que ação cada agente executa, portanto ambos os agentes podem influenciar no resultado.
Assumimos também que os agentes precisam executar uma ação, ou seja, não podem influenciar o resultado ao permanecer inativos, mas precisam escolher entre uma das ações.
Além disso, assumiremos que um agente não pode influenciar e nem sabe qual será a ação
executada pelo outro agente.
Para simplificar ainda mais, assumiremos que cada agente só tem duas opções
de ação para executar. Chamaremos às opções de ‘C’ (cooperar) e ‘A’ (abster-se), terminologia que será utilizada em um exemplo à frente. Seja Ac = {C, A}, o ambiente é
modificado de acordo com a função
τ ∶ Ac × Ac → Ω,
onde a primeira ocorrência de Ac é a ação do agente i e a segunda ocorrência é a
ação de j. Essa função é, essencialmente, uma função de transformação de estados, como
discutido na Seção 1.2.
Eis um exemplo de função de ambiente:
τ (A, A) = ω1 , τ (A, C) = ω2 , τ (C, A) = ω3 , τ (C, C) = ω4 (3.1)
Nessa função, cada combinação de ações dos agentes leva a um resultado diferente. Isso significa que o ambiente é sensível às escolhas dos agentes. Em um outro
extremo, os agente poderiam ser completamente incapazes de influenciar no seu ambiente. Nesse caso, a função de ambiente mapearia todas as combinações de ações para o
mesmo resultado.
τ (A, A) = ω1 , τ (A, C) = ω1 , τ (C, A) = ω1 , τ (C, C) = ω1 (3.2)
No exemplo acima, não importa o que os agentes façam. Uma outra possibilidade é que apenas um dos agentes possa influenciar no ambiente. No exemplo abaixo, o
ambiente varia somente de acordo com as escolhas do Agent j.
τ (A, A) = ω1 , τ (A, C) = ω2 , τ (C, A) = ω1 , τ (C, C) = ω2 (3.3)
153
Como podemos observar, as escolhas de i não interferem no ambiente.
Consideremos novamente o cenário (3.1), em que os dois agentes têm influência
no ambiente, mas agora vamos levar em conta as suas preferências. Suponhamos que as
preferências dos agentes são dadas pelas seguintes funções de utilidade:
ui (ω1 ) = 1 ui (ω2 ) = 1 ui (ω3 ) = 4 ui (ω4 ) = 4
uj (ω1 ) = 1 uj (ω2 ) = 4 uj (ω3 ) = 1 uj (ω4 ) = 4
Nesse caso, podemos relacionar as escolhas dos agentes às utilidades atribuídas a
cada resultado da seguinte maneira:
ui (τ (A, A)) = 1 ui (τ (A, C)) = 1 ui (τ (C, A)) = 4 ui (τ (C, C)) = 4
uj (τ (A, A)) = 1 uj (τ (A, C)) = 4 uj (τ (C, A)) = 1 uj (τ (C, C)) = 4
Neste caso, a preferência do agente i é dada pela ordem parcial
ui (τ (C, C)) ≥ ui (τ (C, A)) > ui (τ (A, C)) ≥ ui (τ (A, A)),
sugerindo que o agent i deve cooperar para obter um resultado mais satisfatório.
Dizemos que essa é a opção racional, pois não há nenhum cenário em que ele tenha
vantagem se agir de maneira diferente.
As preferências dos agentes podem ser apresentadas de maneira concisa em uma
matriz de payoffs:
Figura 7.6. A matrix de payoffs para os agentes i e j.
Em uma matriz de payoffs, o agente i joga de acordo com as colunas e recebe a
recompensa de cima em cada célula. Similarmente, as jogadas do agente j estão representadas nas linhas e a utilidade alcançada em cada caso é o número de baixo em cada
célula.
7.3.3. Extratégias Dominantes
Dado um encontro envolvendo dois agentes i e j, cada um deve decidir sobre que ação
tomar. Um agente decide por sua ações de maneira racional se pesa, em cada escolha,
os possíveis cenários que podem resultar de suas ações e as utilidades destes. Sejam
Ω1 , Ω2 ⊆ Ω, dizemos que Ω1 domina Ω2 se cada resultado em Ω1 é preferível sobre cada
resultado em Ω2 .
154
Por exemplo, considere Ω = {ω1 , ω2 , ω3 , ω4 }, com ui (ω1 ) > ui (ω2 ) > ui (ω3 ) >
ui (ω4 ), Ω1 = {ω1 , ω2 } e Ω2 = {ω3 , ω4 }. Nesse caso, dizemos que Ω1 domina fortemente
Ω2 , pois ui (ω1 ) > ui (ω3 ), ui (ω1 ) > ui (ω4 ), ui (ω2 ) > ui (ω3 ) e ui (ω2 ) > ui (ω4 ).
Uma vez que os conceitos discutidos nessa seção são provenientes de teoria dos
jogos, vamos começar a falar de ações possíveis como estratégias. Dessa forma, os agentes devem escolher que estratégias vão adotar em cada situação. Denotemos por s∗ , o
conjunto de resultados que podem ser alcançados quando o agente i escolhe e joga de
acordo com a estratégia s. Nos exemplos da Seção 3.2, teríamos, portanto, C∗ = {ω3 , ω4 },
enquanto que A∗ = {ω1 , ω2 } para o agente i. Dizemos que uma estratégia s1 domina
fortemente outra estratégia s2 se s∗1 domina fortemente s∗2 . Se uma estratégia si domina
fortemente a todas as outras estratégias acessíveis a um agente, dizemos que si é uma
estratégia dominante.
A intuição por trás de uma estratégia dominante é que esta garante ao agente
alcançar os melhores resultados possíveis, ou seja, maximizar a sua utilidade. Quando
existe uma estratégia dominante, o melhor que o agente tem a fazer é jogar por ela, pois
os desvios podem lhe levar a recompensas menores ou cenários envolvendo perdas.
Quando temos dois ou mais agentes em uma mesma situação, podemos perceber
que, por vezes, as estratégias dominantes de cada agente o são por influência mútua.
Nesse caso, dizemos que as estratégias se encontram em equilíbrio, pois nenhum agente
tem incentivo para desviar-se dessa escolha de estratégias. Esse conceito é o de Equilíbrio
de Nash e é um dos mais importantes em Teoria dos Jogos e na análise de interações entre
agentes. Um cenário de interação entre agentes pode ter zero, um ou vários equilíbrios de
Nash.
7.3.4. O Dilema dos Prisioneiros
Considere o seguinte cenário:
Dois homens são presos e acusados de terem cometido um crime juntos. Os prisioneiros são mantidos em celas separadas e não têm como se comunicar. A cada um dos
homens é dito o seguinte:
1. Se um dos dois confessar o crime, mas o outro não o fizer, o que tiver confessado
será absolvido e o outro cumprirá pena de 3 anos;
2. Se os dois confessarem o crime, cada um receberá dois anos.
Os dois prisioneiros sabem que, se nenhum dos dois confessar, cada um pegará
1 ano de cadeia. A partir de agora, nos referiremos a confessar como cooperar (com a
polícia) e não confessar como abster-se (da oferta). Suponha que você é um dos agentes
e responda: se você fosse um dos prisioneiros, o que faria?
Esse cenário é conhecido como o dilema do prisioneiro. Existem quatro resultados
possíveis para esse cenário, dependendo de que estratégias cada agente escolhe. Tais
resultados são resumidos nas funções
ui (τ (A, A)) = 3 ui (τ (A, C)) = 0 ui (τ (C, A)) = 5 ui (τ (C, C)) = 2
uj (τ (A, A)) = 3 uj (τ (A, C)) = 5 uj (τ (C, A)) = 0 uj (τ (C, C)) = 2.
As funções de utilidade dos agentes, portanto, são:
155
ui (τ (C, A)) > ui (τ (A, A)) > ui (τ (C, C)) > ui (τ (A, C)),
uj (τ (A, C)) > uj (τ (A, A)) > uj (τ (C, C)) > uj (τ (C, A)).
Ilustramos as funções de utilidade dos agentes na seguinte matriz de payoffs:
Figura 7.7. Matrix de payoffs para o dilema dos prisioneiros
Observe que os números na matrix não dizem respeito ao número de anos que
cada agente poderia pegar de cadeia, mas à utilidade vista em cada resultado por cada
agente. Nesse sentido, menos anos de cadeia sugerem uma utilidade maior.
Façamos uma análise para definir o que o agente i deve fazer, colocando-nos em
seu lugar:
• Suponha que eu (agente i) me abstenha da oferta. Nesse caso, se o j também se
abstiver, nós dois teremos um payoff 3 (pena de 1 ano). Se, por outro lado, o j
cooperar, então eu terei um payoff 0 (pena de 5 anos). Portanto, o melhor payoff
que eu posso garantir se eu me abstiver, é 0.
• Suponha, então, que eu coopere com a polícia. Nesse caso, se j se abstiver, eu
fico com um payoff 5, mas se ele cooperar também, eu fico com payoff 2. Assim
sendo, o melhor payoff que eu garanto se cooperar, é 2.
• Se eu me abstiver da oferta, garanto um payoff mínimo de 0, mas se eu cooperar
com a polícia, garanto o payoff mínimo de 2. Consequentemnte, se desejo maximizar a minha utilidade, devo garantir o payoff mínimo de 2. Então eu devo
cooperar com a polícia!
O dilema dos prisioneiros é um exemplo clássico em teoria dos jogos e multiagentes, pois seu resultado é inesperado. Como o cenário de j é idêntico ao de i, seu raciocínio
j deve ser similar. Consequentemente, se i e j agirem de forma racional, os dois cooperarão com a polícia e o resultado será de utilidade 2 para ambos. Observe que o melhor
cenário possível para os agentes é aquele em que os dois decidem por se abster, o que
lhes daria um payoff de 3, mas ambos evitam esse cenário porque há um risco de que o
resultado lhes dê uma utilidade menor.
7.4. Comunicação
Além da interação, a comunicação entre agentes é outro ponto essencial a ser estudado em
sistemas multiagentes. Nesse sentido, devemos destacar que a maioria dos trabalhos sobre
comunicação de agentes está alicerçado na noção de atos de fala, cuja origem remonta-nos
ao livro How to Do Things with Words de Johm Austin [Austin 1962]. Para ele, enunciar
algo pode ser entendido como uma ação física. Nessa linha de estudos, em [Searle 1969]
John Searle identificou vários tipos diferentes de atos de fala:
156
Representativas : tem caráter informativo: "está chovendo".
Diretivas : tenta fazer com que o ouvinte faça algo: "por favor, pegue o chá".
Compromissivas : compromete o falante a fazer algo: "eu prometo que...".
Expressivas : meio pelo qual o falante expressa um estado mental: "muito obrigado".
Declarações : tais como declarar uma guerra ou nomear alguém.
De um modo geral, os atos de fala possuem dois componentes: um verbo performativo(pedir, informar,...) e um conteúdo proposicional ("a porta está fechada"). Observe
que o verbo performativo está relacionado à intenção do ato de fala. Assim, vários atos
de fala diferentes podem ter o mesmo conteúdo proposicional. Veja os seguintes exemplos com o mesmo conteúdo proposicional ("a porta está fechada") gerando três tipos
diferentes de atos de fala à medida que mudamos o verbo performativo:
• performativo = pedir; ato de fala: por favor, feche a porta.
• performativo = informar; ato de fala: a porta está fechada.
• performativo = perguntar; ato de fala: a porta está fechada?
A Foundation for Intelligent Physical Agents (FIPA) começou a trabalhar sobre a
definição de padrões de programas de agentes. Na linguagem desenvolvida por eles, os
atos de fala são caracterizados em termos dos performativos (a FIPA propõe 20 tipos diferentes), personagens envolvidos (remetente, destinatário, etc) e conteúdo proposicional
da mensagem. Na Figura 7.8, temos um exemplo de ato de fala representado em FIPA no
qual o agent1 informa o agent5 que o preço oferecido a good200 é 150.
Figura 7.8. Exemplo de Ato de Fala em FIPA
Em FIPA, "Inform" e "Request" são dois performativos básicos, em termos dos
quais todos os demais são definidos. O significado de "Inform" e "Request" é definido em
duas partes: pré-condição (o que deve ser verdadeiro para o ato de fala ser bem sucedido) e
efeito racional (o que o remetente da mensagem espera ocorrer). No caso do performativo
"Inform", o conteúdo é uma declaração e a sua pré-condição determina que o remetente
acredita que o conteúdo é verdadeiro, pretende que o destinatário acredite na veracidade
do conteúdo e não acredita que o destinatário saiba se o conteúdo seja verdadeiro ou não.
7.5. Alocação de Recursos
Em sociedades de agentes com interesses próprios (self-interested), recursos escassos serão disputados e estarão, com frequência, indisponíveis. Exemplos de recursos escassos
incluem o direito ao uso de um objeto ou recursos computacionais. Tais recursos podem
ser necessários à realização de uma atividade por um agente e, portanto, essencial para
que este alcance um objetivo. Nesse sentido, a alocação de recursos é um problema central em Sistemas Multiagentes e as disputas geradas por escassez devem ser tratadas de
maneira eficiente.
157
Formalmente, dados um conjunto com k recursos R = {o1 , . . . , ok } e um conjunto
com n agentes Agentes = {Ag1 , . . . , Agn }, um problema de alocação de recursos envolve
encontrar uma partição de R com tamanho n, ou seja, conjuntos R1 , . . . , Rn tais que
R1 ∪ ⋅ ⋅ ⋅ ∪ Rn = R, mas Ri ∩ Rj = ∅ para quaisquer Ri , Rj ∈ {R1 , . . . , Rn }. Nesse caso,
cada Ri é o conjunto de recursos alocados para o agente Agi , 1 ≤ i ≤ n.
Os mecanismos utilizados para alocação de recursos dependem essencialmente do
número de agentes e recursos envolvidos no problema. No caso em que há uma pluralidade de agentes, uma forma bastante eficiente de lidar com a distribuição dos recursos é
pela utilização de leilões.
7.5.1. Leilões
Os leilões eram, até pouco tempo, não muito utilizados. A razão era o alto custo para
viabilizar um leilão, dada a necessidade de encontrar um local para o evento, transportar
as mercadorias, contratar um leiloeiro, e mais. A internet mudou isso, reduzindo drasticamente os custos e permitindo realizar e concorrer em leilões a partir de qualquer lugar
do mundo.
Essencialmente, um leilão ocorre entre um agente (o leiloeiro) que controla um
recurso (uma mercadoria) e outros agentes (os licitantes) interessados neste. O objetivo
de um leilão é decidir qual dos licitantes fica com a mercadoria. Para tal, os licitantes
farão ofertas com outros recursos (a exemplo de dinheiro) com o intuito de minimizar o
seu custo, enquanto que o leiloeiro deseja maximar seu ganho. Nesse sentido, se uma
troca é uma atribuição de valores a pagar por uma mercadoria, devemos considerar que:
• Cada agente envolvido atribui um preço limite à mercadoria.
• Um comprador que troca mais do que o seu valor limite pela mercadoria, tem uma
perda.
• Um vendedor que troca sua mercadoria por menos do que o seu valor limite, tem
uma perda.
Uma instituição de mercado define como trocas devem ser feitas. Dessa maneira,
uma instituição define que tipo de mensagens podem ser trocadas e, com base nas mensagens trocadas, quem é o vencedor. O mais comum é que as mensagens sejam restritas
a lances ou pedidos e que a regra que determina o vencedor dificulte a elaboração de
estratégias para vencer o leilão.
Um leilão é uma instituição de mercado em que mensagens entre interessados em
trocas (comerciantes) envolvem alguma informação de valor - uma oferta para comprar a
mercadoria (um lance) ou para vendê-la (um pedido) por um certo valor - e que prioriza
lances de valor maior ou pedidos de valor menor.
7.5.1.1. Leilão Inglês
O leilão inglês é o tipo mais conhecido, consistindo em uma sucessão de propostas públicas, com valor crescente e cujo vencedor é aquele que profere a última (maior) proposta:
• O leiloeiro propõe um preço de reserva (que pode ser 0). Se nenhum agente der
um lance maior, a mercadoria fica com o leiloeiro por esse valor.
158
• Agentes são convidados a dar lances cada vez mais altos, à vontade. Quando
nenhum agente está disposto a aumentar o lance, o leilão é encerrado e o vencedor
paga o valor que propôs.
A estratégia dominante em leilões desse tipo envolve o agente elevar o valor das
propostas aos poucos até atingir o seu valor de reserva e, então, desistir.
7.5.1.2. Leilão Holandês
Este modelo de leilão consiste de propostas públicas, mas decrescentes. Dessa maneira, é
ligeiramente diferente do leilão inglês, mas tal diferença é o bastante para que, em geral,
não haja estratégia dominante.
• O leiloeiro propõe um valor inicial artificialmente alto e segue com ofertas pouco
menores a cada momento.
• Quando um agente aceita a última oferta feita, paga este valor e fica com a mercadoria. Em caso de empate, o leilão é reiniciado com um valor um pouco maior do
que o atual.
7.5.2. Negociação
Em alguns casos, o mecanismo de leilões é insuficiente e outras técnicas mais elaboradas
precisam ser utilizadas. Um dos motivos possíveis para tal é que os leilões dependem
da existência de algum tipo de moeda de troca que permita comparações de valor. Em
um contexto mais geral, tal moeda pode não existir, mas os agentes poderiam que trocar
recursos diversos ou até favores. Nos referimos a essas técnicas, em geral, pelo nome de
negociação. Em uma negociação, os agentes buscam um acordo em situações que sejam
de interesse mútuo.
Em um contexto de negociação teremos ao menos quatro elementos:
• Um conjunto de negociação, com todas as propostas que os agentes podem fazer.
• Um protocolo, o qual define quais propostas são legais em cada momento da negociação, com base em seu histórico.
• Um coleção de estratégias de negociação, uma para cada agente, que determina
quais propostas um agente pretende fazer. Essa estratégia costuma ser privada
para cada agente, embora as propostas, quando feitas, costumem ser públicas.
• Uma regra que determina o fim da negociação e qual seria o acordo alcançado.
Vários fatores podem fazer com que o processo seja bastante complicado, a exemplo do número de itens negociados e do número de envolvidos na negociação. Devido às
dificuldades introduzidas por esses fatores, a maior parte dos trabalhos nesse tema envolve
negociações dos tipos mais simples, envolvendo apenas dois agentes, um único item negociável e em que há simetria, no sentido de que um resultado mais favorável a um dos
agentes é menos favorável ao outro, em igual proporção, e vice-versa. Normalmente,
assume-se que os agentes buscam maximizar sua utilidade durante a negociação e que o
pior resultado possível é a ausência de um acordo.
Uma negociação costuma ser realizada em uma sequência de rodadas que envolvem, cada, uma proposta. A seguir, considere o seguinte modelo para negociação
um-a-um com ofertas alternadas:
159
• Os agentes Ag1 e Ag2 negociam em uma sequência de rodadas 0, 1, 2, . . .
• Nas rodadas pares (r = 0, 2, 4, . . . ):
Ag1 faz uma proposta pr ;
Ag2 aceita ou rejeita pr ; Se aceita, a negociação é finalizada. Caso contrário,
a negociação avança para a rodada r + 1.
• Nas rodadas ímpares (r = 1, 3, 5, . . . ):
Ag2 faz uma proposta pr ;
Ag1 aceita ou rejeita pr ; Se aceita, a negociação é finalizada. Caso contrário,
a negociação avança para a rodada r + 1.
A negociação também pode ser encerrada caso nenhum dos agentes possa fazer
nova proposta após a rejeição da última. Nesse caso, não há acordo. Tão logo a negociação seja finalizada, o acordo a que os agentes chegaram (se chegaram) é implementado.
A Figura 7.9 ilustra uma negociação desse tipo:
Figura 7.9. O ciclo de negociação entre dois agentes.
7.6. Cooperação
Considerando que agentes são autônomos, eles têm que tomar decisões em tempo de execução e devem ser capazes de se coordenarem dinamicamente. No entanto, se os agentes
foram projetados por indivíduos diferentes, eles podem não compartilhar as mesmas metas. Assim por que e como os agentes irão trabalhar juntos? Para responder essa pergunta
precisamos distinguir dois tipos de agentes: agentes benevolentes e os com interesses
próprios.
Se o sistema multiagente foi projetado por uma única pessoa ou organização, é
possível conceber os agentes de um modo tal que eles possam ajudar uns aos outros toda
vez que for preciso. Nesse caso, nós assumimos que os agentes são benevolentes: nosso
melhor interesse é o melhor interesse deles. Nesse caso, a solução de problemas e cooperativa e distribuída, sendo que a presença de agentes benevolentes simplifica enormemente
a projeção do sistema.
160
Por outro lado, se os agentes representam os interesses de indivíduos ou organizações distintas, então nós não poderemos assumir que os agentes serão benevolentes.
Nesse cenário, os gentes serão assumidos como defendendo seus próprios interesses, possivelmente às custas de outros. Não é difícil constatar que a possibilidade de conflitos
é grande, tornando a projeção de tarefas bem mais complicadas. Além disso, pode ser
necessário elaborar estratégias de atuação para que os agentes possam atingir os seus
objetivos, como ocorre, por exemplo, na Teoria de Jogos.
7.6.1. Resolução de Problemas em Conjunto
Ao se tentar resolver um problema cooperativamente em um sistema multiagentes, uma
pergunta fundamental é "como um grupo de agentes trabalha junto para resolver problemas?". Esse trabalho cooperativo pode ser dividido em três estágios: decomposição do
problema, solução do subproblema e síntese da resposta. A seguinte figura, adaptada de
[Wooldridge 2009], ilustra as fases para a solução de problemas de forma cooperativa e
distribuída:
Figura 7.10. Os três estágios para a solução de problemas em cooperação.
Na decomposição do problema, o problema principal é subdividido em subproblemas. Esse processo é normalmente hierárquico/recursivo. Os subproblemas são, por
sua vez, divididos em subproblemas ainda menores, sendo que esse processo continua até
se chegar a um nível atômico razoável. Claramente há como se processar essa divisão.
A questão a ser decidida durante a projeção do sistema é como isso será feito? Outra
questão importante é quem irá fazer a divisão. Será centralizado? Que agentes terão conhecimento da estrutura das tarefas? Que agentes irão resolver cada subproblema? Como
se pode perceber, essa fase de decomposição do problema passa pela resposta de muitas
perguntas.
No próximo estágio, os agentes procurarão solucionar cada um dos subproblemas
gerados. Para tal, eles vão geralmente compartilhar informação durante esse processo.
Além disso, eles terão que sincronizar suas ações quando precisarem dos mesmos recursos
ao mesmo tempo.
Por fim, no estágio de síntese da solução, as soluções dos subproblemas são integradas. Mais uma vez esse processo pode ser hierárquico, permitindo a obtenção de
161
soluções diferentes em diferentes níveis de abstração. Uma questão recorrente nesta fase
é que agente irá fazer essa síntese.
Neste modelo de solução de problemas cooperativamente, muito provavelmente,
nós encontraremos as seguintes atividades:
• Compartilhamento de tarefas: os componentes de uma tarefa são distribuídos entre
os agentes; uma questão a responder é como nós decidimos como alocar tarefas a
agentes?
• Compartilhamento de resultados: informações relevantes à solução de subproblemas (a exemplo de resultados parciais) são compartilhadas entre os agentes do
time por demanda ou pró-ativamente.
A Figura 7.11, adaptada de [Wooldridge 2009], ilustra os conceitos discutidos
acima:
Figura 7.11. (a) Compartilhamento de tarefas e (b) compartilhamento de resultados.
7.6.2. Distribuição de Tarefas com Contract Net
Distribuir tarefas de maneira eficiente entre os agentes de um time pode ser difícil, uma
vez que cada membro do time pode ter capacidades muito diferentes. Nos casos em que
os agentes são realmente autônomos, é concebível que estes possam rejeitar tarefas que
lhes sejam atribuídas e precisem buscar acordos sobre a alocação destas tarefas. Um
protocolo bem conhecido de compartilhamento de tarefas que leva isso em consideração
é o Contract Net. Ele inclui cinco estágios e nos lembra um processo de licitação:
1.
2.
3.
4.
5.
Reconhecimento do Problema
Anúncio da Tarefa
Ofertas
Seleção do contrato
Expedição
Esse protocolo prima por ser autoexplicatório e é ilustrado na Figura 7.12.
Apesar de sua simplicidade, o Contract Net se tornou o framework mais implementado e melhor estudado para a solução de problemas com distribuição de tarefas.
7.7. Coordenação
Talvez o problema principal no que tange o trabalho cooperativo em grupos de agentes é
o da coordenação entre os envolvidos. Este problema concentra-se no gerenciamento de
162
Figura 7.12. Protocolo Contract Net
dependências entre as atividades dos agentes para que estas possam interagir de maneira
apropriada. As dependências entre atividades vão desde os requisitos para seu início ao
cumprimeiro de regras que garantem a consistência do sistema.
Considere o seguinte exemplo, corriqueiro na vida real:
Duas pessoas estão em uma sala e, ao mesmo tempo, resolvem sair. Há uma única
porta na sala e sua largura só permite que uma pessoa passe por vez. Nesse caso, há um
recurso público (a porta) que ambos desejam usar, mas do qual apenas um pode usufruir
por vez. Como consequência, as atividades das pessoas precisam ser coordenadas para
que não haja uma colisão e todos possam cumprir os seus objetivos.
Os agentes de uma sociedade também podem usar de coordenação para evitar a
repetição de esforços, nesse caso, agindo de forma coordenada e cooperativa. No exemplo
acima, se a porta deve permanecer fechada quando ninguém estiver utilizando a passagem,
as ações necessárias a cada agente envolveriam abrir a porta, sair e fechar a porta. Se o
primeiro que passar pela porta perceber que há outra e, invés de executar todos os passos,
deixar a porta aberta, alguns esforços são evitados.
Existem diversas abordagens para coordenar dinamicamente as atividades de
agentes em um sistema. Entre estas abordagens, pode-se modelar os agentes desde o
começo para que ajam coordenadamente, desenhar regras que induzam à coordenação
de atividades ou promover a comunicação das intenções dos agentes à sociedade. Neste
capítulo, vamos nos concentrar em apenas uma dessas abordagens, a dizer, baseada em
normas e leis sociais.
163
7.7.1. Normas e Leis Sociais
Sociedades são frequentemente reguladas por regras (muitas vezes não-escritas) de comportamento. Por exemplo, um grupo de pessoas está esperando numa parada de ônibus.
O ônibus chega; quem entra no ônibus primeiro? Num sistema multiagentes, nós teremos
que projetar as normas que o programa dos agentes deve seguir ou formalizar aspectos do
ambiente e dos agentes de maneira que essas normas possam emergir. Vamos agora dar
mais detalhes sobre esses dois tipos de normais sociais:
Antes de descrever como projetar as normas que o programa dos agentes deve
seguir, é válido destacar que nós descrevemos agentes como
Ag ∶ RE → Ac,
ou seja, uma função que dada uma execução terminando num estado, retorna uma ação.
Uma restrição é um par
⟨E ′ , α⟩ ,
em que E ′ ⊆ E é um conjunto de estados e α ∈ Ac é uma ação. Essa restrição afirma
que α não pode ser realizada em qualquer estado em E ′ . Uma lei social é definida, então,
como um conjunto dessas restrições.
Nós ainda podemos refinar nossa visão de um ambiente. Para tal, vamos chamar
de estados focais, F ⊆ E, aqueles que nós queremos nosso agente seja capaz de estar.
De qualquer estado focal e ∈ F , deve ser possível chegar a qualquer outro estado focal
(embora não necessariamente de maneira direta). Uma lei social útil é uma que não
previne agentes de chegar de um estado focal a outro.
No que tange às normas sociais, nós também podemos projetar sistemas
em que elas podem emergir.
Um conhecido exemplo é o jogo da camiseta
[Shoham and Tennenholtz. 1997]:
"Agentes têm ambos uma camiseta vermelha e uma azul e vestem uma delas. O
objetivo é que cada cada agente termine com a mesma cor. Em cada rodada, cada agente
encontra-se com um outro agente e decide se muda de camiseta ou não. Durante a rodada,
eles veem somente a camiseta de que seu par estiver vestindo (eles não obtêm nenhuma
outra informação)". Que função de atualização de estratégia eles deveriam usar? Na
sequência, estão algumas funções de atualização que poderiam ser aplicadas nesse caso:
• Maioria simples: agentes pegam a camiseta que eles viram com mais frequência.
• Maioria simples com tipos: agentes estão divididos em dois tipos; quando eles
encontram um agente do mesmo tipo, eles compartilham suas memórias. Caso
contrário, eles agem como no caso de maioria simples.
• Recompensa cumulativa mais alta: para essa atualização funcionar, agentes devem
ser capazes de perceber que adotando certa estratégia irá produzir um resultado
particular. A regra de atualização baseada na recompensa cumulativa mais alta
estabelece que um agente use a estratégia que produza o resultado cumulativo
mais alto até o momento.
164
Referências
Austin, J. L. (1962). How To Do Things With Words. Oxford University Press.
Ferguson, I. A. (1992). TouringMachines: An Architecture for Dynamic, Rational, Mobile
Agents. PhD thesis, Computer Laboratory, University of Cambridge, Cambridge, UK.
Genesereth, M. R. and Nilsson, N. (1987). Logical Foundations of Artificial Intelligence.
Morgan Kaufmann.
Müller, J. P. and Pischel, M. (1993). The agent architecture inteRRaP : concept and application. Technical report, Saarländische Universitäts- und Landesbibliothek; Sonstige
Einrichtungen. DFKI Deutsches Forschungszentrum für Künstliche Intelligenz.
Searle, J. R. (1969). Speech Acts: an Essay in the Philosophy of Language. Cambridge
University Press.
Shoham, Y. and Tennenholtz., M. (1997). On the emergence of social conventions: modeling, analysis and simulations. Artificial Intelligence, 94(1):139–166.
Steels, L. (1990). Cooperation between distributed agents through self organization. In
Demazeau, Y. and Müller, J.-P., editors, Decentralized AI - Proceedings of the 1st European Workshop on Modelling Autonomous Agents in a Multi-Agent World(MAAMAW89), pages 175–196. Elsevier.
Wooldridge, M. (2009). An Introduction to MultiAgent Systems. Wiley Publishing, 2nd
edition.
Wooldridge, M. and Jennings, N. R. (1995). Intelligent agents: theory and practice. The
Knowledge Engineering Review, 10(2):115–152.
165
Capítulo
8
Desenvolvimento para dispositivos móveis que
utilizam plataforma iOS
Roniel Soares de Sousa, José Almí Soares Filho, Ricardo Teles Freitas,
Kelson Aires, André Soares, Vinicius Machado, Laurindo Britto Neto
Laboratório de Inteligência Computacional (LabInC) da Universidade
Federal do Piauí (UFPI)
Abstract
This chapter describes the main principles for the applications development for iOS
devices – iPhone, iPad and iPod Touch. The main tool required for such activity, the
Xcode, is presented. Moreover, this work will approach the Objective-C programming
language, Views’ manipulation, the use of the iOS Simulator – tool used for testing the
applications – and even the connectivity technologies’ functionality (Bluetooth and WiFi).
Resumo
Este capítulo descreve princípios fundamentais para o desenvolvimento de aplicativos
para dispositivos que utilizam a plataforma iOS – iPhone, iPad e iPod Touch.
Apresentar-se-á a principal ferramenta necessária nesta atividade, o Xcode. Além
disso, este trabalho abordará a linguagem de programação Objective-C, manipulação
de “Views”, o uso do iOS Simulator – ferramenta utilizada para testar as aplicações –
e até mesmo o funcionamento de tecnologias de conectividade (Bluetooth e Wi-Fi).
8.1. Introdução
Esta seção apresenta o iOS SDK, kit de desenvolvimento de sistemas para iOS. É
coberto desde a sua instalação até a definição dos principais componentes.
8.1.1. Obtendo o iOS SDK (Software Development Kit)
O iOS SDK é um conjunto de aplicações necessárias para desenvolver aplicativos para
dispositivos móveis (conhecidos popurlamente como apps), que rodam nativamente no
166
iOS. Ele fornece uma grande variedade de programas que dão suporte ao desenvolvedor
nas etapas de produção do app.
Para obter acesso ao iOS SDK, é necessário inicialmente possuir uma conta na App
Store (loja virtual de aplicativos para iOS). Abaixo está o link para download:
- http://itunes.apple.com/us/app/xcode/id448457090?mt=12
Além disso, você precisa de um Mac baseado em Intel com o Mac OS Snow Leopard ou
superior instalado.
O iOS SDK é dividido em diferentes componentes que auxiliam no desenvolvimento das
aplicações. Tais componentes são: Xcode, DashCode, iOS Simulator, e Instruments.
Dentre eles, os mais utilizados aqui serão o Xcode e o iOS Simulator.
NOTA: Neste minicurso será considerada a versão 4 do SDK, versão mais atual no
momento da confecção deste minicurso.
8.1.2. Componentes do SDK
O SDK do iOS inclui as seguintes ferramentas:
• XCode - Ambiente de desenvolvimento integrado através do qual o programador
gerencia, edita e depura os projetos.
• Dashcode - Ambiente de desenvolvimento integrado voltado para produzir
aplicações web para iOS, assim como Dashboard Widgets.
•
iOS Simulator - Simulador do iOS.
•
Interface Builder - Editor gráfico para projetar interfaces, que está integrado ao
XCode desde a versão 4. Nas versões anteriores o Interface Builder não
compunha o XCode mas vinha separado no SDK.
•
Instruments - Programa que visa analisar o desempenho dos apps.
O SDK do iOS também inclui outras aplicações. Entretanto, este minicurso está focado
apenas no XCode, Interface Builder, e no iOS Simulator. Nas próximas seções tais
componentes serão detalhados.
8.1.2.1. XCode
O XCode é o principal ambiente, onde se desenvolvem as aplicações, tanto na sua parte
gráfica, com auxílio de um construtor de interfaces gráficas que auxilia de maneira
bastante intuitiva na criação da interface, quanto na sua parte funcional, feita através do
código escrito em Objective-C.
Este ambiente de desenvolvimento integrado (IDE) permite que o programador comece
sua aplicação a partir de modelos pré definidos (templates):
•
•
•
Navigation-­based application: Tema que viabiliza um ponto de partida para uma aplicação com controle de navegação. OpenGL ES Application: Permite utilizar uma visualização na qual é possível renderizar uma cena OpenGL ES. Split View-­based Application: Começa uma aplicação com uma visualização do tipo dividida e duas visualizações comuns. 167
•
•
•
•
Tab Bar Application: Começa uma aplicação com um controlador de barra e um controlador de visualização do primeiro item da barra. Utility Application: Inicia uma aplicação com uma visualização principal e uma outra do tipo “flipside”. View-­based Application: Provem uma visualização com um controlador e um arquivo .nib. Window-­based Application: Template inicial para qualquer tipo de aplicação. Alguns desses templates são exclusivos para determinados dispositivos, mesmo rodando
sobre a mesma plataforma. Por exemplo o template Split-View Based serve apenas para
iPad.
8.1.2.2. iOS Simulator
Outra ferramenta importante que o SDK fornece é o simulador que imita o
funcionamento de um iPhone, iPad ou iPhone Retina utilizando o iOS.
É importante notar que esta ferramenta é um simulador, ou seja ela tenta imitar o
comportamento do iOS nos dispositivos baseando-se no MAC OS para compilar o
código da aplicação. Isso significa que ela irá usar as bibliotecas presentes no MAC para
fazer a aplicação se comportar como se estivesse num verdadeiro iPhone, embora em
um dispositivo real a aplicação precise ser compilada para o byte-code usado nele. O
iPhone utiliza um código baseado na arquitetura ARM para isso.
O simulador apresenta algumas características importantes do dispositivo real. Entre
elas estão os movimentos de toque: toque leve, duplo toque e pinça, rotações de tela e
simulações de avisos de pouca memória. Porém outras características importantes como
fazer ligações, utilizar a câmera ou o acelerômetro não estão disponíveis até a versão 4.3
do simulador.
8.1.2.3. Interface Builder (Integrado ao Xcode)
O Interface Builder favorece a construção de interfaces gráficas para o usuário,
fornecendo elementos gráficos baseados no drag-and-drop (arrastar e soltar) e formas
intuitivas de conectar tais elementos com o código.
Os conceitos de Outlets e Actions são essenciais para se compreender como são ligados
os elementos gráficos do Interface Builder com as funcionalidades do código.
8.2. Objective-C
A Objective-C é uma linguagem de programação orientada a objeto, desenvolvida pela
Apple, a fim de ser usada tanto no desenvolvimento para MAC OS X quanto para o iOS.
É uma extensão da linguagem C padrão, portanto quem já possui certa experiência com
a programação em C não terá problemas na adaptação ao Objective-C.
Para entender o código de uma aplicação em tal linguagem é preciso saber como são
divididos seus arquivos:
• .h – Arquivos de cabeçalho, onde se localizam as declarações de objetos e
métodos.
• .m – Arquivos de implementação, como sugere o próprio nome, contém a
implementação do que foi declarado nos arquivos de cabeçalho.
168
A seguir veremos algumas características da Linguagem Objective-C.
8.2.1. Diretivas
Para incluir bibliotecas na implementação de código usa-se o pré-processador de
diretivas, no caso do Objective-C, o #import, que atua de forma igual ao #include no C
ou C++.
8.2.2. Classes
Como Objective-C é uma linguagem orientada a objetos, existe a necessidade de um
certo conhecimento sobre classes.
Para declarar uma classe usa-se @inteface, como no exemplo a seguir:
@interface NomeDaClasse : NSObject {
}
@end
NSObject refere-se a classe da qual a classe declarada herda.
Já na implementação de uma classe usa-se @implementation além da declaração da
mesma. Veja o exemplo:
#import “NomeDaClasse”
@implementation NomeDaClasse
//implementação
@end
Entretanto, podem ocorrer casos de importação cíclica, onde uma determinada classe,
que será chamada de “ClasseUm”, tem como atributo uma instância de uma certa
“ClasseDois” e vice-versa, tendo assim a necessidade de cada uma ser importada na
outra. Para evitar isso, faz-se necessário o uso de @class como mostrado abaixo:
#import<Foundation/Foundation.h>
@class ClasseDois;
@interface ClasseUm : NSObject{
ClasseDois *classeDois;
}
@end
#import <Foundation/Foundation.h>
@class ClasseUm;
@interface ClasseDois : NSObject{
ClasseUm *classeUm;
169
}
@end
8.2.3. Instanciando classes
Para criar uma instância de determinada classe em Objective-C, devemos usar a palavra
“alloc”, que permite reservar um espaço na memória para o novo objeto. Além disso,
usa-se o caractere ‘*’ (asterisco) precedendo o nome da variável que irá referenciar o
objeto criado, exceto nos casos em que a variável é de tipo primitivo. O trecho abaixo
exemplifica a criação de um objeto:
ClasseQualquer *classeQualquer = [ClasseQualquer alloc];
8.2.4. Métodos
Como qualquer linguagem orientada a objetos, em Objective-C existem métodos.
Métodos são funções definidas dentro de uma classe e podem ser de dois tipos:
•
Métodos de instância: são usados apenas através da instância de uma classe e em
Objective-C são precedidos pelo caractere ‘-‘. Exemplo:
- (void) facaAlgo {
//Implementação
}
Caso existam parâmetros:
- (void) facaAlgo:(NSString *) outroParametro: (NSInteger *){
//Implementação
}
Para fazer a chamada de métodos de instância:
[objeto metodo];
Caso existam parâmetros:
[objeto metodo: parametro1 outroParametro: parametro2];
•
Métodos de classe: São usados diretamente com o nome da classe, não se
fazendo necessária a existência de uma instância. Em Objective-C são
precedidos pelo caractere ‘+’. Exemplo:
+ (void) facaAlgo {
//Implementação
}
Caso existam parâmetros:
+ (void) facaAlgo:(NSString *) outroParametro: (NSInteger *){
170
//Implementação
}
Para fazer a chamada de métodos de classe:
[classe metodo];
Caso existam parâmetros:
[classe metodo: parametro1 outroParametro: parametro2];
8.2.5. Privilégios de acesso
Os campos de uma classe não devem ser acessados de qualquer forma, pois a alteração
de um desses campos indevidamente pode causar erros. Para evitar que isso aconteça
existem os privilégios de acesso. Por padrão os campos em Objective-C são do tipo
@protected, mas existem ainda 2 outros tipos, veja a lista:
• @protected – Campo visível tanto na classe em que foi declarada quanto nas que herdam da mesma. •
@public – Campo visível em todas as classes.
•
@private – Campo visível apenas na classe em que foi declarado.
Exemplo de como mudar o privilégio de acesso de um campo:
#import<Foundation/Foundation.h>
@class OutraClasse;
@interface ClasseQualquer : NSObject{
OutraClasse *outraClasse;
@public float rate;
@public NSString *name;
}
@end
8.2.6. Propriedades
As propriedades permitem um maior controle sobre como os campos da classe são
definidos ou retornados, sendo mais útil que os privilégios de acesso vistos
anteriormente. Elas criam automaticamente os chamados “assessores” (getters e setters).
Exemplo de como definir um campo como propriedade:
#import <Foundation/Foundation.h>
@class OutraClasse;
@interface ClasseQualquer : NSObject{
OutraClasse *outraClasse;
float rate;
NSString *name;
171
}
@property float rate;
@property (retain, nonatomic) NSString *name;
-(void)doSomething;
-(void) doSomething:(NSString*)str;
-(void)doSomething:(NSString*) strwithAnotherPara:(float)value;
+(void)alsoDoSomething;
@end
Já na implementação usa-se o operador @synthesize como a seguir:
#import“ClasseQualquer.h”
@implementation ClasseQualquer
@synthesize rate, name;
Veja que após o operador @property do campo “name” foram colocadas as palavras
“retain” e “nonatomic”, elas são as responsáveis pelas modificações na definição e no
modo como o campo é retornado.
8.2.7. Inicializadores
Quando uma instância de uma classe é criada existe a necessidade de inicializá-la. Em
Objective-C é usada a palavra-chave “init” para a inicialização dessa instância.
Entretanto, também há a possibilidade de criar inicializadores adicionais, definindo-se
métodos iniciados com “init”.
Exemplo de inicialização:
[[ClasseQualquer alloc] init];
Exemplo de inicializadores adicionais:
#import<Foundation/Foundation.h>
@class OutraClasse;
@interface ClasseQualquer:NSObject{
OutraClasse *OutraClasse;
float rate;
NSString *name;
}
@property float rate;
@property (retain,nonatomic) NSString *name;
-(void)doSomething;
-(void)doSomething:(NSString*) str;
172
-(void)doSomething:(NSString*) strwithAnotherPara: (float)value;
+(void)alsoDoSomething;
- (id)initWithName:(NSString *) n;
- (id)initWithName:(NSString *) n andRate:(float) r;
@end
E a implementação é feita da seguinte forma:
#import“SomeClass.h”
@implementationSomeClass
@synthesizerate,name;
- (id)initWithName:(NSString *) n {
return [self initWithName:n andRate:0.0f];
}
- (id)initWithName:(NSString *) n andRate:(float) r {
if (self = [super init]) {
self.name = n;
self.rate = r;
}
return self;
}
8.2.8 Protocolos
Protocolos funcionam de forma bem parecida às interfaces de programação, porém com
a diferença que o programador pode escolher o que a classe vai implementar ou não.
Assim existe a possibilidade de se adicionar um protocolo e usar apenas um método
declarado por ele. Para melhor entendimento veja o trecho abaixo:
UIAlertView*alert=[[UIAlertViewalloc] initWithTitle:@”Hello”
message:@”This is an alert view”
delegate:self
cancelButtonTitle:@”OK”
otherButtonTitles:@”Option 1”, @”Option 2”, nil];
[alertshow];
O código anterior ilustra um alerta na tela, isso será explicado mais detalhadamente na
seção 9.4. O trecho em negrito é usado quando se quer adicionar botões ao alerta, e para
saber qual botão foi clicado é necessário manipular métodos declarados no protocolo
UIAlertViewDelegate.
Os protocolos devem ser adicionados no arquivo .h da classe em que se quer
implementar, como no explicitado no exemplo a seguir:
173
@interface
ObjCTestViewController:UIViewController <UIAlertViewDelegate> {
//Declaração de atributos
}
@end
Agora basta fazer a implementação do método desejado no arquivo .m.
8.3. Anatomia de um aplicativo para iOS e “Hello World”
Para exemplificar a criação de um projeto, vamos desenvolver um aplicativo “Hello
World”. Para isto, siga as seguintes etapas:
1. Abra o Xcode e você verá a tela de boas vindas como mostra a Figura 8.1. Acesse
File  New  New Project para criar um novo projeto.
2. Você poderá observar na nova janela os vários tipos de projetos que podem ser
criados, conforme explicado anteriormente. Escolha “View-based Application” e
clique em Next.
3. Na próxima janela, nomeie o projeto para “HelloWorld” e em Device Family escolha
iPhone. Clique em Next e escolha o local onde deseja salvar o projeto. No lado
esquerdo da nova janela você poderá observar os vários arquivos gerados com o
projeto.
Assim como em qualquer aplicativo em C, em Objective-C o programa é inicializado
por uma função main, que no nosso projeto está localizada na pasta Supporting Files,
dentro do arquivo main.m. Porém, é necessário editá-lo. Foram criadas duas classes com
o nosso projeto. A primeira, “HelloWorldAppDelegate”, receberá e manipulará
importantes mensagens durante o tempo de execução do aplicativo. Já a
“HelloWorldViewController” é a primeira visualização, que foi criada automaticamente
porque escolhemos “View-Based Application” na hora da criação do projeto.
Observe
o
método
(BOOL)application:
(UIApplication*)
applicationdidFinishLaunchingWithOptions: (NSDictionary*) launchOptions presente
no arquivo HelloWorldAppDelegate.m. Ele será invocado assim que o aplicativo for
inicializado completamente. Observe que ele é o responsável pela exibição da primeira
visualização, que é uma instância da classe HelloWorldViewController.
4. No
lado
esquerdo,
realize
um
clique
simples
“HelloWorldViewController.xib” para exibir o Interface Builder.
174
no
arquivo
5. No canto superior direito, existem botões para exibir novas áreas na janela. Clique no
botão de utilitários, como destacado na Figura 8.1, para exibir a área de Utilitários.
Figure 8.1. Interface Builder.
6. No canto inferior direito, observa-se a biblioteca de objetos. Clique e arraste um
Label para o Interface Builder. Aumente o tamanho do label. Depois, com o label
selecionado, clique no ícone “Attributes Inspector” para editar o mesmo. Na tag
name, digite Hello World. Sua janela deverá ficar como na Figura 8.2.
Figura 8.2. Colocando um label na aplicação.
175
7. Por fim, clique no botão Run, localizado no canto superior esquerdo. O iOS
Simulator deverá abrir automaticamente e exibir o aplicativo com o Hello World,
conforme ilustra a Figura 8.3.
Figura 8.3. iOS Simulator com Hello World.
8.4. Actions e Outlets
Outlets e Actions são dois dos principais conceitos que você tem que entender para
programar para iOS.
Quando o objetivo é utilizar atributos de uma determinada classe como referência para
algum objeto criado pelo Interface Builder, é necessário declará-los como “Outlet”.
Para isto, basta declarar o atributo no arquivo .h como segue abaixo:
IBOutlet <Class> *<var>;
em que <Class> representa o nome da classe a que pertence o atributo, e <var> é o
nome da variável. Ex: IBOutlet NSString *nome;
Caso o atributo não fosse declarado com a tag IBOutlet, ele não poderia ser visualizado
pelo Interface Builder.
Para ligar o Outlet a algum objeto do Interface Builder, siga os passos abaixo:
1. Com o projeto anterior aberto, vá no arquivo HelloWorldViewController.h e adicione
o código destacado abaixo:
…
@interface HelloWorldViewController : UIViewController {
176
IBOutlet UIButton *button;
}
…
2. Clique no arquivo HelloWorldViewController.xib, insira um Round Rect Button logo
abaixo do Label “Hello World” e renomeio para “Enviar”, da mesma maneira que foi
inserido o label.
3. Clique com o botão direito no ícone File Owner, arraste para o botão criado e solte.
Será exibida uma janela com os “Outlets” disponíveis para seleção, escolha “button”.
Figura 8.4. Outlets.
Pronto, agora você já pode manipular o botão criado no Interface Builder através do
atributo “button” criado no .h. Vamos exemplificar isto alterando o nome do botão.
Para
isto,
implementaremos
o
método
viewDidLoad
no
arquivo
HelloWorldViewController.m. Você pode observar que este método já existe, porém
está em forma de comentário. Descomente-o e adicione o código destacado abaixo:
-(void)viewDidLoad
{
[button setTitle:@”Novo” forState:UIControlStateNormal];
[super viewDidLoad];
}
Pressione Run para testar, se tudo tiver ocorrido como o esperado, o iOS Simulator
deverá exibir o botão com o nome “Novo”.
177
Já quando deseja-se que algum método seja invocado por algum objeto do Interface
Builder, é necessário declará-lo no arquivo .h como segue abaixo:
-
(IBAction) <metodo> …;
em que <metodo> receberá o nome do método. A utilização de parâmetros segue
normalmente. Ex: -(IBAction) imprimeNome:(NSString*) nome;
Para exemplificar a utilização de Actions, siga o exemplo abaixo:
1. Com o projeto anterior aberto, vá no arquivo HelloWorldViewController.h e adicione
o código destacado abaixo:
…
@interface HelloWorldViewController : UIViewController {
IBOutlet UIButton *button;
}
-(IBAction) buttonPressed;
…
2. Vamos agora implementar o método criado. Para isto , abra o arquivo
HelloWorldViewController.m e adicione o código destacado abaixo.
…
@implementation HelloWorldViewController
-(void) buttonPressed
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Funcionou"
message:@"Voce pressionou o botão.”
delegate:self cancelButtonTitle:@"Ok"
otherButtonTitles:nil];
[alert show];
[alert release];
}
…
O que fizemos foi criar um alerta e exibí-lo toda vez que o método for chamado.
3. Abra o arquivo HelloWorldViewController.xib. Clique com o botão direito no botão
“Enviar” e arraste para File Owner (sentido contrário ao feito com o Outlet). Será
exibida uma janela com os eventos disponíveis, escolha “buttonPressed”. Com isso,
toda vez que o botão for pressionado, ele chamará o método “buttonPressed”.
4. Salve o projeto, clique em “Run” e pressione o botão “Novo”. Se tudo tiver ocorrido
como o esperado, será exibido um alerta como mostra a Figura 8.5. Clique em Ok
para fechar o alerta.
178
Figura 8.5. IBAction, Alerta.
8.5. Adicionando views
8.5.1. Window-Based Application
Até então o único template do XCode explorado foi o “View-based application” que já
traz um controlador de visualizações e uma visualização ligada à janela principal da
aplicação. Para o projeto alcançar essa etapa, primeiramente, ele foi desenvolvido a
partir de um template básico chamado “Window-based application”. Este template
oferece somente o alicerce para qualquer aplicação que rode em iPhone, e todo o
restante deve ser criado pelo programador. A vantagem de se usar um template assim é
que qualquer tipo de aplicação com qualquer tema inicial pode surgir de uma aplicação
“Window-based”, em contrapartida, por ser um template muito básico, o desenvolvedor
precisa construir toda a aplicação “quase do zero”.
O programador deve escolher, de acordo com suas necessidades, o template adequado
para sua aplicação. Se nenhum template for “correto” para o tipo de aplicação que o
desenvolvedor almeja, então ele pode começar a aplicação a partir do template
“Window-based application” e fazer todo o app da maneira que desejar.
Agora iremos mostrar como o template “View-based application” é criado a partir do
“Window-based application”. Para isso será criada uma visualização e um controlador
de visualizações ao projeto.
1. Crie um projeto no XCode para uma aplicação iOS com o template “Windowbased application”, coloque o nome “Window” e selecione a opção destinado a
iPhone.
2. Clique no arquivo “WindowAppDelegate.xib”, isso irá mostrar a janela principal do
app. Note que, ao rodar o aplicativo neste ponto, será possível ver apenas uma tela
179
branca sem nenhuma visualização dentro, diferente de um template “View-based”
que traz uma tela cinza. Isto ocorre porque não há um controlador de visualizações
nem mesmo uma visualização vinculada ao aplicativo.
3. Agora vá no menu View/Utilities/ e clique em “Show Object Library”, uma coluna no
lado direito da tela surgirá com os objetos na parte de baixo.
4. Arraste o objeto “View Controller” para qualquer local do editor fora da janela
principal do app, isto irá exibir outra janela ao lado da principal. Neste passo você
está inserindo um controlador de visualizações como objeto na instância que
representa a janela principal do projeto.
5. Clique com o botão direito do mouse na pasta que tem o nome do projeto no
navegador de projeto, coluna mais à esquerda do XCode. Na janela selecione a opção
“New File” e então escolha o template do tipo iOS Cocoa Touch chamado
“UIVIewController subclass”. Marque a opção “With XIB for user interface”, clique
em “Next”, nomeie a classe para “primeiraView” e selecione o local para salvá-la.
Agora você tem um programa mais modularizado com uma visualização separada
para usar no projeto. Essa visualização ainda não está associada à janela principal do
app, no entanto você já pode trabalhar nela.
6. Selecione o arquivo “primeiraView.xib” que foi gerado do passo anterior e insira um
objeto UIButton chamado “Round Rect Button” que pode ser encontrado na
biblioteca de objetos (coluna da direita no canto inferior). Realize um duplo clique
nele e nomei-o para “Visualização conectada”. Ao rodar o aplicativo neste ponto
você perceberá que, mesmo tendo alterado a visualização do arquivo que acabou de
inserir, ainda não será possível acessá-la no app, pois ela ainda não está vinculada à
janela principal.
7. Selecione o outro arquivo, “MainWindow.xib”, e clique no objeto “View Controller”.
Acesse o menu View/Utilities/ e clique em “Show Identity Inspector”, ele irá aparecer
no canto direito do construtor gráfico. Em “Custom Class” selecione a classe que
você criou no passo 5. Agora vá no inspetor de atributos, clicando em “Show
Attributes Inspector” em View/Utilities/, no campo “NIB Name” escreva o nome da
classe que você criou no passo 5. Aperte Command + S.
8. Clique no arquivo WindowAppDelegate.h e adicione o seguinte trecho de código que
está em negrito:
#import <UIKit/UIKit.h>
@class primeiraView;
@interface mesaAppDelegate : NSObject <UIApplicationDelegate>
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet primeiraView *teste;
@end
Ao fazer isso você está declarando um atributo para o
WindowAppDelegate da aplicação e ele será visível no construtor de interface.
180
objeto
9. Agora clique no arquivo WindowAppDelegate.m e adicione o trecho de código que
está em negrito:
#import "mesaAppDelegate.h"
#import "primeiraView.h"
@implementation mesaAppDelegate
@synthesize window = _window,teste;
(BOOL)application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
// Override point for customization after application launch.
[_window addSubview:teste.view];
[self.window makeKeyAndVisible];
}
return YES;
- (void)dealloc//
Últimas linhas
{
[teste release];
[_window release];
}
[super dealloc];
10.Vá ao MainWindow.xib, clique com o botão direito do mouse no ícone do objeto
Window App Delegate e arraste para o ícone primeiraView. Irá aparecer uma
pequena janela com o nome do atributo do tipo primeiraView criado na interface
WindowAppDelegate.h, clique nele e salve. Esse movimento representa a conexão
entre o atributo criado para o objeto WindowAppDelegate e a classe que você
inseriu.
11.Pressione Command + R para rodar a aplicação. Ela deverá exibir a tela da classe
inserida no passo 5. Este projeto que começou com o template Window-based
Application é agora uma aplicação idêntica a uma que começa como o template
View-based application.
8.5.2. Adicionando Views dinamicamente
Outra maneira de se adicionar uma visualização é através do código. Dessa maneira
pode-se colocar uma visualização com o aplicativo em execução, característica que
deverá ser bastante explorada pelo desenvolvedor para aliviar a quantidade de
elementos da primeira visualização, deixando o código mais modularizado e legível.
O objeto UIView que será adicionado dinamicamente funciona como um container para
outras visualizações como botões, textos, campos de texto e até mesmo para um outro
container. A primeira visualização do projeto servirá de base para suportar o objeto que
será inserido dinamicamente, portanto, este objeto dependerá da base para existir.
181
Para adicionar uma visualização dinamicamente, inicie um projeto do tipo “View-based
application” destinado a iPhone com o nome viewBased.
1. Clique no arquivo viewBasedViewController.xib, insira um objeto “Round Rect
Button” e nomeie-o para “Mudar Visualização”, aperte Command + S. Esse botão
vai servir de gatilho para mudar da primeira para a segunda visualização.
2. Adicione um novo arquivo do tipo “UIViewController” com o nome
“novaVisualizacao”. Clique no arquivo .xib gerado por ele, adicione um “Label” e
coloque o nome “Nova Visualização” nele. Essa nova classe vai gerar o objeto que
será usado na segunda visualização.
3. Clique no arquivo viewBasedViewController.h, e acrescente o seguinte trecho de
código em negrito e aperte Command + S:
#import <UIKit/UIKit.h>
@class novaVisualizacao;
@interface docsViewController : UIViewController
@property(nonatomic, retain) novaVisualizacao *nova;
-(IBAction)mudarVisualizacao;
@end
A nova visualização será declarada como um atributo da primeira com o nome “nova”.
4. Clique agora no arquivo da implementação viewBasedViewController.m, acrescente
o trecho de código em negrito e aperte Command + S:
#import "docsViewController.h"
#import "novaVisualizacao.h"
@implementation docsViewController
@synthesize nova;
…
-(IBAction)mudarVisualizacao{
nova = [[novaVisualizacao alloc] init];
[self.view addSubview:nova.view];
}
…
-(void)dealloc{
[nova release];
[super dealloc];
}
O método mudarVisualizacao, que será acionado pelo botão “Mudar Visualização”, irá
criar um objeto da classe que você inseriu no passo 2 e associá-lo ao atributo “nova”. O
182
método “addSubview” chamado pelo campo “view” irá colocar a segunda visualização
em cima da primeira e a partir de agora o usuário irá interagir com ela.
5. Agora vá ao viewBasedViewController.xib, clique com o botão direito do mouse no
elemento UIButton que você inseriu no primeiro passo, arraste para o “File’s Owner”
e selecione o método que aparece na tela. Agora está feita a vinculação que fará o
botão da interface chamar o método.
6. Clique em Command + R para executar o projeto.
8.5.3. Animando a transição de visualizações
A implementação anterior mostra uma transição brusca de uma visualização
para outra, sem nenhum efeito visual para deixar a aplicação mais agradável. Os apps,
no entanto, devem apresentar recursos estéticos para tornar a aplicação mais aprazível e
consequentemente atrair mais usuários. Um desses efeitos disponíveis pelo framework
UIKit é o de transição de visualizações. Para mostrar como é implementado o efeito
você pode aproveitar o projeto anterior.
1. Clique em <NomeDoProjeto>ViewController.m e dentro do corpo do método
mudarVisualizacao insira o seguinte trecho em negrito:
(IBAction)mudarVisualizacao
{
self.nova = [[novaVisualizacao alloc] init];
[UIView beginAnimations:@"Curl" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDuration:.4];
[UIView
setAnimationTransition:UIViewAnimationTransitionCurlUp
forView:self.view cache:YES];
[self.view addSubview:nova.view];
[UIView commitAnimations];
}
Essa série de métodos da classe UIView serve para customizar a animação de
transição e esta transição pode ser aplicada a qualquer objeto da classe UIView.
2. Aperte Command + R para rodar o projeto.
8.6. Suporte a multi-plataformas para iPhone e iPad
Por ter o mesmo sistema operacional que o iPhone e o iPod Touch, o iPad pode rodar
aplicativos desenvolvidos para ambos dispositivos. Porém, a visualização do aplicativo
183
na tela do iPad terá a mesma dimensão usada pelo iPhone. Isso significa um grande
desperdício, visto que a tela do iPad possui uma dimensão maior que a tela do iPhone.
Para resolver esse problema, a Apple recomenda que se crie aplicações universais
alterando apenas a interface de usuário. Veja a seguir como isso é feito (Figura 8.6):
1. Usando o Xcode, crie uma “View-based application” (para iPhone) e nomeie-o
como “Universal”.
2. Abra o UniversalViewController.xib adicione um “Label” e mude seu texto para
“iPhone application”.
3. Na tela inicial do projeto, em targets, selecione o aplicativo e em devices, selecione
Universal. Então clique em YES.
Figura 8.6. Tornando o aplicativo multiplataforma.
4. Veja que foi criada uma pasta para recursos do iPad. Crie uma nova classe do tipo
UIViewController destinada a iPad e nomeie como iPadUniversal.
5. Edite o novo .xib criado.
6. Selecione MainWindow-iPad.xib para que seja editado no Interface Builder. Agora
selecione o item Universal View Controller e no inspetor de identidade coloque
Class como “iPadUniversal”.
7. Agora em inspetor de atributos defina NIB Name como “iPadUniversal”. Dessa forma o aplicativos terá duas interfaces de usuário, sendo cada uma iniciada no
dispositivo para o qual foi desenvolvido.
184
8.7. Rotação de tela
Os dispositivos que utilizam iOS possuem a capacidade de detectar a orientação da
interface. Assim existe a possibilidade de adequar a interface do usuário à nova
orientação, nesta seção descreve como é feita a rotação.
Por padrão o projeto no Xcode é criado com suporte a única orientação, para habilitar
mas
múltiplas
orientações
é
preciso
sobrescrever
o
método
“shouldAutorotateToInterfaceOrientation”. Esse método é chamado sempre que a
orientação muda e retorna ‘YES’ caso esteja em orientação “Portrait” (retrato). Então
basta mudá-lo para que sempre retorne ‘YES’ de modo que o método fique como a
seguir:
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
Agora, para colocar cada objeto em seu lugar na tela siga o passo-a-passo:
1. Crie um projeto “View-Based Application” no Xcode, nomeie-o ScreenRotations e
edite-o no Interface Builder adicionando um botão.
2. No arquivo ScreenRotationsViewController.h adicione o seguinte código:
#import <UIKit/UIKit.h>
@interface ScreenRotationsViewController : UIViewController {
IBOutlet UIButton *btn;
}
@property (nonatomic, retain) UIButton *btn;
@end
1. No Interface Builder, conecte o Outlet que você criou clicando com botão direito do
mouse e arrastando até o Rounded Rect Button. Selecione btn.
2. No arquivo ScreenRotationsViewController.m adicione o seguinte código:
#import “ScreenRotationsViewController.h”
@implementation ScreenRotationsViewController
@synthesize btn;
-(void) positionViews {
UIInterfaceOrientation destOrientation = self.interfaceOrientation;
if (destOrientation == UIInterfaceOrientationPortrait ||
destOrientation == UIInterfaceOrientationPortraitUpsideDown) {
//---if rotating to portrait mode--btn.frame = CGRectMake(20, 20, 233, 37);
} else {
185
btn.frame = CGRectMake(227, 243, 233, 37);
}
}
- (void)willAnimateSecondHalfOfRotationFromInterfaceOrientation:
(UIInterfaceOrientation) fromInterfaceOrientation
duration:(NSTimeInterval) duration {
[self positionViews];
}
- (void)viewDidLoad {
[self positionViews];
[super viewDidLoad];
}
- (void)dealloc {
[btn release];
[super dealloc];
}
8.8. Conectividade
Serviços de conexão no iOS podem ser feitos de várias maneiras. Podem ser usadas
redes wi-fi ou bluetooth para conectar dispositivos. No entanto, o iOS Simulator apenas
utiliza rede wi-fi para fazer as simulações. Ao simular uma conexão Bluetooth o
simulador vai, efetivamente, utilizar a rede wi-fi.
Nesta sessão mostraremos como fazer uma conexão entre dois aparelhos via bluetooth.
Para isto, utilizaremos o Game Kit, que é um framework que contém APIs que permitem
a comunicação através de uma rede bluetooth.
Instanciaremos a classe GKSession para representar uma sessão entre dois dispositivos
conectados. Também utilizaremos uma instância da classe GKPeerPickerController,
que providência uma interface gráfica para procurar e conectar com outros dispositivos.
Para isto, siga os seguintes passos:
1. Crie um novo projeto utilizando o template View-Based Application, nomeie-o
“Bluetooth”. Adicione o GameKit.framework ao projeto. Para isto, acesse Targets
 Build Phases  Link Binary With Libraries, clique no sinal ‘+’ e selecione o
GameKit.framework. 2. Adicione 3 botões, 1 label e 1 Text Field ao BluetoothViewController.xib e
renomeie-os como mostra a Figura 8.7. 186
Figura 8.7. Interface.
3. Em BluetoothViewController.h, adicione o código destacado abaixo: #import <UIKit/UIKit.h>
#import <GameKit/GameKit.h>
@interface BluetoothViewController : UIViewController <GKSessionDelegate,
GKPeerPickerControllerDelegate> {
GKSession *currentSession;
GKPeerPickerController *picker;
}
IBOutlet
IBOutlet
IBOutlet
IBOutlet
@property
@property
@property
@property
UIButton* conectar;
UIButton* disconectar;
UIButton* enviar;
UITextField *texto;
(nonatomic,
(nonatomic,
(nonatomic,
(nonatomic,
retain)
retain)
retain)
retain)
GKSession *currentSession;
UITextField *texto;
UIButton *conectar;
UIButton *disconectar;
-(IBAction) btnSend:(id) sender;
-(IBAction) btnConectar:(id) sender;
-(IBAction) btnDisconectar:(id) sender;
@end
4. Conecte os botões e o Text Field aos seus respectivos atributos pelo Interface
Builder, como já foi feito com projetos anteriores. Faça o mesmo com os métodos. 5. Em BluetoothViewController.m, adicione o código destacado abaixo para
implementar os métodos necessários: @synthesize conectar,desconectar,texto,currentSession;
-(IBAction) btnConectar:(id) sender {
picker = [[GKPeerPickerController alloc] init];
picker.delegate = self;
187
}
picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;
[conectar setHidden:YES];
[desconectar setHidden:NO];
[picker show];
-(IBAction) btnDesconectar:(id) sender {
[self.currentSession disconnectFromAllPeers];
[self.currentSession release];
currentSession = nil;
[conectar setHidden:NO];
[desconectar setHidden:YES];
}
-(void)peerPickerController:(GKPeerPickerController *)pk
didConnectPeer:(NSString *)peerID toSession:(GKSession *)session {
self.currentSession = session;
session.delegate = self;
[session setDataReceiveHandler:self withContext:nil];
picker.delegate = nil;
[picker dismiss];
[picker autorelease];
}
-(void)peerPickerControllerDidCancel:(GKPeerPickerController *)pk {
picker.delegate = nil;
[picker autorelease];
[conectar setHidden:NO];
[desconectar setHidden:YES];
}
-(void)session:(GKSession *)session peer:(NSString *)peerID
didChangeState:(GKPeerConnectionState)state {
switch (state) {
case GKPeerStateConnected:
NSLog(@"Conectado");
break;
case GKPeerStateDisconnected:
NSLog(@"Desconectado");
[self.currentSession release];
currentSession = nil;
[conectar setHidden:NO];
[desconectar setHidden:YES];
break;
}
}
-(void)session:(GKSession *)session didFailWithError:(NSError *)error {
NSLog(@"%@",[error description]);
}
- (void) mySendDataToPeers:(NSData *) data {
if (currentSession)
[self.currentSession sendDataToAllPeers:data
withDataMode:GKSendDataReliable
error:nil];
}
-(IBAction) btnSend:(id) sender {
NSData* data;
NSString *str = [NSString stringWithString:texto.text];
data = [str dataUsingEncoding: NSASCIIStringEncoding];
[self mySendDataToPeers:data];
}
188
- (void) receiveData:(NSData *)data fromPeer:(NSString *)peer
inSession:(GKSession *)session context:(void *)context {
NSString* str;
str = [[NSString alloc] initWithData:data
encoding:NSASCIIStringEncoding];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Informacao
recebida"
message:str delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
[str release];
}
- (void)dealloc
{
[texto release];
[currentSession release];
[conectar release];
[desconectar release];
[super dealloc];
}
- (void)viewDidLoad
{
[conectar setHidden:NO];
[desconectar setHidden:YES];
[super viewDidLoad];
}
6. Rode o projeto e pressione o botão Conectar. O método btnConectar será chamado quando o botão “Conectar” for pressionado. Ele configura e exibe o PickerController. Figura 8.8. PeerPickerController
189
Quando algum dispositivo for encontrado, o picker exibirá uma lista com esses
dispositivos, para que o usuário possa escolher com qual deseja se conectar. Após
selecionar dispositivo para conexão, será exibida uma interface de espera, até que o
outro dispositivo aceite a conexão. Caso a conexão seja aceita, o método session: peer:
didChangeState: será chamado automaticamente. Ao enviar uma mensagem, o método
btnSend transformará o texto em Data e enviará a informação através do método
mySendDataToPeers. Ao receber uma mensagem, o método receiveData: fromPeer:
inSession :context será invocado, decodificará a informação em String e a exibirá em
um alerta.
8.9. – Considerações finais
Este minicurso abordou princípios fundamentais e alguns conceitos mais técnicos
relacionados a programação para a plataforma de dispositivos móveis iOS. Ele teve
como objetivo servir de ponto de partida para aqueles que desejam se aprofundar mais
na programação para o sistema operacional móvel da Apple. Para isto, recomenda-se a
leitura dos livros mencionados na bibliografia.
8.10. - Bibliografia
− ALI, Maher. Advanced iOS 4 programming: developing mobile applications for Apple iPhone, iPad and iPod Touch. Wiley. EUA: 2010. 698 p. − LEE, Wei-­‐Meng. Beginning iOS 4 development application. Wiley. EUA: 2010. 631 p. − iOS Dev Center <http://developer.apple.com/devcenter/ios/index.action>. Acessado em 23/09/2011, às 14:37. 190
Capítulo
9
Desenvolvimento Rápido de Aplicações Móveis
Utilizando a Linguagem Declarativa QML
Ricardo Erikson V. S. Rosa, Adriano M. Gil, Paulo R. B. Mendonça, Cícero
F. F. Costa Filho e Vicente F. Lucena Jr.
Abstract
The emerging software development technologies have their focus on reducing the timeto-market of new products. In the mobile applications context, reduce time-to-market is
critical to maximize ROI. QML (Qt Meta-object Language) is part of a declarative UI framework known as Qt Quick which aims to facilite the rapid development of applications.
This course aims to present the main components and features of the QML language and
Qt Quick UI framework addressed to the development of mobile applications.
Resumo
As novas tecnologias de desenvolvimento de software buscam meios de reduzir o tempo
excessivo gasto na criação de novos produtos. No contexto de aplicações móveis, reduzir o tempo que um produto leva para chegar ao mercado é crítico para maximizar
o retorno sobre investimento. QML é uma linguagem declarativa que facilita o desenvolvimento rápido de interfaces do usuário (UIs) e consequentemente reduz o tempo de
desenvolvimento. Este minicurso tem por objetivo apresentar os principais componentes
e características da linguagem QML e do framework Qt Quick com foco em aplicações
móveis.
9.1. Introdução
Desenvolvedores de aplicações móveis buscam meios de reduzir o tempo excessivo gasto
na criação e publicação de novos produtos. No mercado das app stores, as lojas online
de aplicativos, o desenvolvedor precisa considerar três parâmetros de tempo: (1) tempo
de desenvolvimento, (2) time to shelf (intervalo de tempo entre a submissão de uma aplicação e sua publicação para compra na loja) e (3) time to payment (período de tempo
entre a venda da aplicação e os rendimentos chegarem até o desenvolvedor). A redução
191
do intervalo de tempo compreendido entre o início do desenvolvimento e o retorno dos
rendimentos é um fator crítico para maximizar o ROI.
Levando em consideração o tempo de desenvolvimento, a rapidez na codificação e
na prototipagem dos aplicativos é apontada como uma das principais razões técnicas para
que os desenvolvedores escolham uma plataforma de desenvolvimento [10]. Os resultados
de codificação e prototipagem são muitas vezes apresentados na forma de interfaces do
usuário (UIs). No entanto, a dificuldade de criação dessas UIs, onde os usuários têm que
aprender novas APIs inteiramente sem levar em conta as experiências de desenvolvimento
em outras plataformas, é destacada como um dos problemas comumente enfrentado pelos
desenvolvedores em várias plataformas [9, 10].
QML (Qt Meta-objects Language) é uma linguagem declarativa utilizada no kit
de desenvolvimento Qt Quick (Qt User Interface Creation Kit) [8] que faz parte do framework Qt1 . QML é utilizada no desenvolvimento de aplicativos cross-platform e busca
facilitar o projeto e a implementação de UIs para dispositivos móveis através da rapidez
na codificação e na prototipagem. O estilo de programação da linguagem QML é baseado
nas linguagens CSS (Cascading Style Sheets) e JavaScript, tornando-se de aprendizado rápido e fácil para programadores C, Qt/C++, Java e principalmente desenvolvedores web.
Diferentemente de outras linguagens de programação que utilizam a abordagem
imperativa para construir as UIs, QML utiliza o paradigma declarativo. A utilização desse
paradigma permite que os desenvolvedores descrevam UIs declarando somente os objetos
que devem ser exibidos, ou seja, sem descrever o fluxo de controle ou sequência de ações
que devem ser executadas para criar a interface. Enquanto a UI é criada de maneira declarativa, a lógica da aplicação pode ser escrita de maneira imperativa através das linguagens
JavaScript e C++. Isso facilita a separação entre a UI e a lógica da aplicação, permitindo
que projetos Qt/C++ baseados no padrão model-view-controller (MVC) sejam facilmente
portados para QML [1, 2].
Uma das principais características da linguagem QML é a flexibilidade na criação
das UIs. Essa flexibilidade é possível graças à possibilidade de adicionar e manipular
elementos como formas, imagens e texto. Outros elementos como estados, transições,
animações, transformações, efeitos gráficos e elementos de interação permitem a criação
de aplicações mais sofisticadas em QML, principalmente quando utilizados em conjunto
com JavaScript e C++.
Este capítulo tem o objetivo de apresentar a linguagem QML e sua utilização no
desenvolvimento rápido de aplicações móveis. Os principais características da linguagem são apresentados na Seção 9.2. A utilização dos elementos no tratamento de eventos
é demonstrada na Seção 9.3. A Seção 9.4 mostra os principais elementos utilizados na
criação de animações. Os mecanismos de criação de componentes customizados são descritos na Seção 9.5. As particularidades das principais plataformas de desenvolvimento
são mostradas na Seção 9.6 e, por fim, as considerações finais são feitas na Seção 9.7.
1 Qt
é um framework de desenvolvimento de aplicações cross-platform que foi desenvolvido em C++ e
está disponível para Windows, Linux e Mac OS X. O framework disponibiliza um amplo conjunto de APIs
que podem ser utilizadas no desenvolvimento para plataformas móveis embarcadas e desktop.
192
9.2. Linguagem Declarativa QML
Muitas plataformas móveis disponibilizam APIs, em linguagens de programação comumente conhecidas (por exemplo Symbian C++, Qt/C++, Java, e Objective-C), para que
os desenvolvedores criem as UIs dos aplicativos. Porém, muitas vezes o custo de aprendizado de uma API inteira, considerando também as particularidades da sintaxe de cada
linguagem, é bastante alto [9]. Além disso, o paradigma imperativo, que é frequentemente
empregado nas linguagens de programação modernas, faz com que o processo de criação
das UIs se torne árduo e demorado [12]. Baseando-se nesses fatos, o desenvolvimento
cross-platform utilizando plataformas que possibilitem baixo custo de aprendizado e rápida prototipagem parece ser uma alternativa desejável no desenvolvimento de aplicativos
móveis.
A linguagem declarativa QML fornece um ambiente de programação bastante
simples e flexível, porém robusto. Ela dispõe de um amplo conjunto de componentes,
para a criação das UIs, e de mecanismos de integração (bindings) com as linguagens
JavaScript e Qt/C++. Os objetos da UI dos aplicativos QML são especificados por elementos que possuem tipo e propriedades (no estilo nome:valor, como em CSS), o que
torna a linguagem intuitiva e de fácil aprendizado tanto para designers de UI quanto para
programadores. Para ilustrar isso, as Listagens 9.1 e 9.2 apresentam uma comparação
entre as linguagens Qt/C++ e QML para a criação de um simples elemento visual.
O código Qt/C++ necessário para desenhar um retângulo é apresentado na Listagem 9.1. Esse código exibe o retângulo na UI e define propriedades como largura, altura
e cor.
1 void paint(QPainter *painter,
2
const QStyleOptionGraphicsItem *option,
3
QWidget *widget){
4
QRect rect(0, 0, 200, 100);
5
painter->setBrush(QBrush(Qt::green));
6
painter->drawRect(rect);
7 }
Listagem 9.1. Código Qt/C++ necessário para exibir um retângulo.
A Listagem 9.2 exibe o código QML necessário para desenhar o mesmo retângulo.
O retângulo criado consiste em um único objeto do tipo Rectangle com 3 propriedades
(width, height e color).
1 import QtQuick 1.0
2 Rectangle {
3
width: 200
4
height: 100
5
color: "green"
6 }
Listagem 9.2. Código QML necessário para exibir um retângulo.
193
9.2.1. Ambiente de Desenvolvimento
O ambiente necessário para o desenvolvimento de aplicativos em QML é disponibilizado
juntamente com o QtSDK [5], que pode ser obtido em http://qt.nokia.com/downloads. O
QtSDK inclui o Qt Quick e disponibiliza a ferramenta Qt QML Viewer [6], que é muito
utilizada no desenvolvimento e depuração de código QML, mas não deve ser utilizada em
ambiente de produção. Outra opção disponível no SDK é a utilização da IDE Qt Creator,
que fornece um ambiente completo para o desenvolvimento de aplicativos em Qt/C++ e
QML.
Uma aplicação QML é executada através da máquina de execução QML, também
chamada de QML runtime, para ser executada. Existem duas maneiras de se iniciar essa
máquina de execução: (1) a partir de uma aplicação Qt/C++ (utilizando a classe QDeclarativeView) ou (2) através da ferramenta Qt QML Viwer2 . Aplicativos QML destinados
ao usuário final (para instalação e utilização no dispositivo móvel) devem utilizar a primeira opção. Já os aplicativos quando ainda em processo de desenvolvimento podem ser
testados utilizando o Qt QML Viewer.
Os exemplos apresentados nas próximas seções podem ser testados utilizando o
Qt QML Viewer. Porém, mais adiante neste capítulo, será apresentado como invocar
aplicativos QML utilizando código Qt/C++.
9.2.2. Propriedades e Tipos de Dados
Os objetos QML são especificados por meio de seus elementos e cada elemento possui
um conjunto de propriedades. Essas propriedades são formadas por pares nome-valor
(por exemplo, color:“blue”) e assumem uma variedade de tipos de dados que podem ser
referências para outros objetos, strings, números, etc. Em QML, as propriedades são
fortemente tipadas, ou seja, se uma propriedade possui um tipo específico então um valor
de tipo diferente não pode ser atribuído à ela. A Tabela 9.1 apresenta alguns dos tipos de
dados comumente utilizados em propriedades QML.
Objetos definidos em QML podem ser referenciados por outros objetos por meio
da propriedade id. Essa propriedade é definida explicitamente pelo programador para
identificar um objeto dentro do escopo QML. Dessa maneira, o valor de uma propriedade
de um determinado objeto podem ser externamente acessado por <id>.<propriedade>,
como na linha 5 da Listagem 9.3 com obj2.width.
Uma propriedade pode ser expressada em função de outra propriedade do mesmo
objeto (ou de um objeto diferente, por meio de seu id) desde que possuam tipos compatíveis. Dessa maneira, se o valor da propriedade referenciada for alterado durante a
execução aplicação, a máquina de execução QML recalcula a expressão e atualiza o valor
da propriedade que fez a referência. Por exemplo, na Listagem 9.3 a propriedade height
é definida pela expressão obj2.width*2. Então, se o valor da propriedade width for alterado, o valor de height será automaticamente atualizado, alterando também a aparência
visual do objeto.
QML permite que novas propriedades sejam declaradas na definição de um objeto.
Ainda na Listagem 9.3 (linha 7), a propriedade area, que não faz parte da definição
2 Para
testar o aplicativo é necessário executar o seguinte comando: $ qmlviewer arquivo.qml
194
Tabela 9.1. Alguns tipos utilizados no sistema de tipagem da linguagem QML.
Tipo
color
bool
date
time
font
int
double
real
list
point
rect
size
string
url
Descrição
Nomes de cores especificadas no padrão SVG [11] entre aspas. Os valores também podem ser especificados nos formatos “#RRGGBB” ou
“#AARRGGBB”.
Pode assumir os valores true ou false.
Data especificada no formato “YYYY-MM-DD”.
Horário especificado no formato “hh:mm:ss”.
Encapsula as propriedades de uma instância do tipo QFont do Qt.
Representa valores inteiros.
Possui ponto decimal e seus valores são armazenados com precisão dupla.
Representa um número real.
Representa uma lista de objetos.
Representa um ponto através das coordenadas x e y.
Consiste na representação dos atributos x, y, width e height.
Consiste na representação dos atributos width e height.
Texto livre entre aspas.
Representa a localização de algum recurso, como um arquivo, através de seu
endereço.
original do tipo Rectangle, é definida como sendo o produto width*height. O valor
dessa propriedade é atualizado pela máquina de execução QML sempre que os valores de
width e height são alterados.
1 import QtQuick 1.0
2 Rectangle {
3
id: obj1
4
width: 200
5
height: obj2.width*2
6
color: "#008000"
7
property real area: width*height
8 }
Listagem 9.3. Exemplos da utilização de propriedades na linguagem QML.
9.2.3. Elementos Básicos
A linguagem QML oferece um conjunto de elementos que permitem a rápida e fácil inclusão de objetos nos aplicativos. Esses elementos podem ser aninhados permitindo a criação
de um relacionamento do tipo pai-filho (parent-child) entre eles. Esse tipo de relacionamento pode ser muito útil para a criação de layouts baseados em pontos de ancoragem,
que será apresentado na Seção 9.2.4.
Uma lista dos elementos mais básico comumente encontrados em QML está disponível na Tabela 9.2. Esses elementos, através de suas propriedades e seus sinais 3 ,
3 Sinais
(de sinais e slots) é uma característica muito importante no tratamento de eventos do framework
195
Tabela 9.2. Alguns elementos básicos disponíveis na linguagem QML.
Elemento
Item
Rectangle
Image
Text
TextInput
MouseArea
Descrição
O elemento mais básico da linguagem QML. Embora não possua aparência visual, ele é utilizado como base de todos os elementos visuais.
É um dos elementos mais básicos para a criação de aplicações em QML.
É utilizado para preenchimento de áreas e é frequentemente utilizado
como base para o posicionamento de outros elementos.
O elemento é utilizado para exibir imagens na UI. Todos os formatos
suportados pelo Qt podem ser utilizados no elemento Image, incluindo
PNG, JPEG e SVG.
É utilizado para adicionar texto na UI.
Esse elemento possibilita a entrada de texto no aplicativo, podendo restringir o formato dos dados de entrada través da utilização de uma máscara de validação.
É um elemento invisível, frequentemente utilizado em conjunto com
elementos visíveis, no tratamento de eventos de entrada com o ponteiro
do mouse ou toques na tela.
possibilitam a criação das UIs e o tratamento de eventos em aplicativos móveis. Uma
lista mais completa dos elementos QML pode ser encontrada em [4].
9.2.4. Layouts Baseados em Pontos de Ancoragem
O layout baseado em pontos de ancoragem é um poderoso recurso proporcionado pela linguagem QML e é muito útil no posicionamento dos objetos na UI dos aplicativos. Cada
elemento QML possui basicamente seis pontos invisíveis de ancoramento: left, right,
top, bottom, horizontalCenter e verticalCenter. Esses pontos possibilitam a criação
de relacionamentos entre as linhas de ancoragem de diferentes objetos. Em outras palavras, esses pontos facilitam o posicionamento de um objeto em relação a outros objetos
adjacentes.
A Figura 9.1 apresenta um exemplo da utilização de pontos de ancoragem com
dois elementos do tipo Rectangle. O código apresentado a esquerda (Figura 9.1(a))
realiza a ancoragem da borda esquerda do objeto obj2 à borda direita do objeto obj1.
Dessa maneira, obj2 sempre fica localizado à direita de obj1. O resultado visual da
utilização desses pontos de ancoragem é apresentado na Figura 9.1(b).
Múltiplos pontos de ancoragem podem ser especificados por objeto. Esse tipo de
abordagem permite maior flexibilidade no posicionamento dos objetos assim como melhor ajuste da UI do aplicativo. Isso pode ser muito útil na adaptação de aplicativos para
execução em dispositivos com tamanhos de tela diferentes. Uma das abordagens utilizadas por designers gráficos é criar áreas de flutuação (que variam de tamanho) para facilitar
o reajuste dos objetos da UI em tamanhos de tela variados. A utilização de ancoragem
permite que os valores de largura e/ou altura dessas áreas sejam ajustados sem que sejam
Qt. Os sinais são emitidos com a intenção de comunicar eventos que ocorrem na aplicação. Os slots, por
sua vez, são funções que são chamadas respondendo aos sinais, ou seja, aos eventos.
196
1
2
3
4
5
6
7
8
9
Rectangle {
id:obj1; ...
Text {text: "obj1"; ...}
}
Rectangle {
id:obj2; ...
Text {text: "obj2"; ... }
anchors.left: obj1.right
}
(a) Código
(b) Resultado
Figura 9.1. Ancoragem da borda direita do objeto obj1 à borda esquerda do objeto obj2.
definidos explicitamente.
A Figura 9.2(a) apresenta o código para a criação de uma área que é redimensionada dependendo do posicionamento dos outros objetos. Na definição do objeto obj2,
o ponto top foi ancorado ao bottom do objeto obj1, e o ponto bottom foi ancorado ao
top do objeto obj3. Como resultado, a propriedade height do objeto obj2 é dependente
do posicionamento dos objetos obj1 e obj3, não necessitando defini-la explicitamente. O
resultado visual dessa ancoragem é apresentado na Figura 9.2(b).
1
2
3
4
5
6
7
8
9
10
11
12
13
Rectangle {
id: obj1; ...
x: 0; y: 0; width: 120
}
Rectangle {
id: obj2; ...
anchors.top: obj1.bottom
anchors.bottom: obj3.top
}
Rectangle {
id: obj3; ...
x: 0; y: 200; width: 120
}
(a) Código
(b) Resultado
Figura 9.2. Exemplo da utilização de ancoragem para a criação um objeto que varia a propriedade height automaticamente.
Uma propriedade de ancoragem muito útil e frequentemente utilizada para o preenchimento de objetos é o anchors.fill. Essa propriedade convenientemente fixa as âncoras left, right, top e bottom de um objeto às âncoras left, right, top e bottom de um
objeto alvo. Essa propriedade é muitas vezes utilizada pelo tipo MouseArea para criar
uma área clicável com as mesmas dimensões de um outro objeto.
Outra propriedade de conveniência bastante utilizada é o anchors.centerIn. Essa
propriedade é utilizada para automaticamente centralizar um objeto em relação à outro
objeto. A propriedade anchors.centerIn fixa as âncoras verticalCenter e horizontal-
197
Center de um objeto às âncoras verticalCenter e horizontalCenter de outro objeto.
9.2.5. Criando a Primeira Aplicação QML
Como explicado anteriormente na Seção 9.2.1, para que seja instalada e executada no
dispositivo móvel, uma aplicação QML precisa ser executada a partir de uma aplicação
Qt/C++ utilizando a classe QDeclarativeView. A IDE Qt Creator possui templates que
facilitam a criação de projetos para executar aplicações QML. No lado esquerdo da tela de
criação de novos projetos do Qt Creator, deve ser escolhido um projeto do tipo Qt Quick
Project, e no lado direito, um template do tipo Qt Quick Application.
Após a escolha do nome do projeto e sua localização, é necessário escolher o
target. Dentre as opções de target apresentadas, normalmente são escolhidas duas opções
para auxiliar no desenvolvimento de aplicações móveis: Desktop e Remote Compiler. A
opção Desktop é utilizada para compilação e execução da aplicação no próprio desktop
durante o desenvolvimento. Já a opção Remote Compiler é utilizada para a compilação
dos aplicativos para plataformas móveis específicas.
No projeto criado, o arquivo principal da aplicação (main.cpp) possui o código que
executa o arquivo QML principal, conforme apresentado na Listagem 9.4. Nesse exemplo, o objeto viewer do tipo QmlApplicationViewer é configurado e define o arquivo
QML principal como sendo “qml/ERCEMAPI/main.qml” (linha 10). Em seguida, o método showExpanded() do objeto viewer apresenta a o arquivo QML na tela do aplicativo,
conforme apresentado na linha 11.
O tipo QmlApplicationViewer é um tipo definido no template de criação do projeto e é do tipo QDeclarativeView. O QmlApplicationViewer é uma classe de conveniência criada com configurações específicas de código para cada plataforma móvel, como
orientação de tela e debug.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Arquivo: main.cpp
#include <QtGui/QApplication>
#include "qmlapplicationviewer.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QmlApplicationViewer viewer;
viewer.setOrientation(
QmlApplicationViewer::ScreenOrientationAuto);
viewer.setMainQmlFile(QLatin1String("qml/ERCEMAPI/main.qml"));
viewer.showExpanded();
return app.exec();
}
Listagem 9.4. Arquivo Qt/C++ principal de uma aplicação QML executável no dispositivo
móvel.
Na Listagem 9.5 encontra-se o arquivo “main.qml”, que possui código QML principal da aplicação. Esse código possui uma aplicação simples que exibe uma mensagem
“Olá Mundo QML” e exibe uma imagem com o logo do Framework Qt ao se clicar em
198
botão. Logo na primeira linha do arquivo, é declarada a instrução import QtQuick 1.0,
utilizada para importar os principais elementos da linguagem QML. A seguir é declarado
um elemento do tipo Rectangle como a base do aplicativo. É interessante observar que o
elemento Item também pode ser utilizado para criar essa base para a construção do aplicativo. Nas linhas seguintes, o restante da aplicação é construída declarando-se objetos
dos tipos Image, Rectangle, Text e MouseArea.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Arquivo: main.qml
import QtQuick 1.0
Rectangle {
width: 640; height: 360
color: "white"
Image {
id: img
y: 250
source: "qt.png"
visible: false
anchors.horizontalCenter: parent.horizontalCenter
}
Rectangle {
color: "limegreen"; width: 150; height: 50; radius: 5
anchors.horizontalCenter: parent.horizontalCenter; y: 50
Text {
anchors.centerIn: parent;
font { family: "Helvetica"; pointSize: 20 }
text: "Clique aqui"
}
MouseArea {
anchors.fill: parent
onClicked: {
msg.text = "Olá Mundo QML"
img.visible = true
}
}
}
Text {
id: msg;
font { family: "Helvetica"; pointSize: 40 }
anchors.centerIn: parent; text: ""
}
}
Listagem 9.5. Arquivo QML principal com o código da aplicação.
9.3. Tratamento de Eventos
Um dos pontos mais importantes no desenvolvimento de software para dispositivos móveis é o tratamento de eventos, pois é através desses eventos que ocorre a interação entre
o usuário e a aplicação. Nesta seção serão abordadas as principais maneiras de interação
com o usuário através do mecanismo de tratamento de eventos utilizado na linguagem
QML e no framework Qt Quick.
199
9.3.1. Sistema de Eventos Baseado em Sinais
O tratamento de eventos da linguagem QML é similar ao mecanismo de sinais e slots disponível no framework Qt. Em QML os sinais são emitidos para notificar a ocorrência de
eventos e estão conectados a slots específicos (também conhecidos como manipuladores
de sinais ou signal handlers). Esses slots, por sua vez, permitem que código JavaScript
seja executado em resposta à um evento. Dessa maneira, sempre que um determinado sinal associado a um evento for emitido, o slot associado a esse sinal é chamado e o código
JavaScript contido nele é executado.
Cada elemento QML possui seus próprios slots, cada um associado a um sinal ou
mesmo à uma propriedade. No caso dos sinais, os slots seguem uma sintaxe padrão do
tipo: on<Sinal>. Por exemplo, o tipo MouseArea possui o sinal clicked e um slot associado chamado onClicked. De maneira semelhante, cada propriedade possui um slot associado às mudanças de valor através da seguinte sintaxe: on<Propriedade>Changed.
Por exemplo, o slot onWidthChanged refere-se ao slot da propriedade width. Assim,
sempre que ocorrerem alterações no valor dessa propriedade, seu slot correspondente será
chamado.
O código exibido na Listagem 9.6 apresenta um exemplo de tratamento de evento
de clique em um elemento do tipo MouseArea. Esse código fecha a aplicação executando
o comando JavaScript quit() disponível na variável global Qt.
1 MouseArea {
2
anchors.fill: parent
3
onClicked: {
4
Qt.quit();
5
}
6 }
Listagem 9.6. Tratamento de evento de clique no elemento MouseArea.
Ao declarar novos sinais ou propriedades, o framework Qt Quick automaticamente
cria slots seguindo as convenções de nomenclatura apresentadas anteriormente. Logo, é
possível construir um sistema próprio de eventos, estendendo os sinais e slots básicos
providos pelo framework Qt Quick. Por exemplo, ao implementar um teclado virtual,
seria interessante que a assinatura do sinal tivesse um parâmetro para enviar o valor da
tecla pressionada ao slot quando o sinal for emitido.
O código exibido na Listagem 9.7 mostra como um teclado virtual poderia ser implementado em QML. O elemento Rectangle não possui um sinal que é emitido na ocorrência de eventos de clique, e tão pouco um slot para tratar esses eventos. Dessa maneira,
um sinal clicked(string value) é declarado recebendo como argumento um valor do tipo
string (linha 5). Ao declarar esse sinal, o slot onClicked é criado automaticamente no
objeto button do tipo Rectangle. No slot onClicked do elemento MouseArea, o sinal
button.clicked(string value) é emitido e passa como argumento o valor buttonText.text
(linha 13). No slot onClicked do objeto button, essa propriedade pode ser acessada através do parâmetro value passado pelo sinal clicked(string value), conforme apresentado
na linha 15.
200
1 import QtQuick 1.0
2
3 Rectangle {
4
id: button; ...
5
signal clicked(string value)
6
Text {
7
id: buttonText
8
anchors.centerIn: parent
9
text: "A"
10
}
11
MouseArea {
12
anchors.fill: parent
13
onClicked: button.clicked(buttonText.text)
14
}
15
onClicked: console.log(value)
16 }
Listagem 9.7. Trecho de código da implementação de um teclado virtual com sinais e slots
customizados.
9.3.2. Elementos de Interação
O mais primário tipo de interação que um usuário espera ter com um software moderno se
dá através de interações de mouse ou outro mecanismo apontador. Esse tipo de interação
não limita-se somente aos cliques. Na verdade, existem vários outros eventos como botão
pressionado, botão solto, movimento, etc. Com a crescente popularização das telas de
toque em dispositivos móveis, como tablets e smartphones, outros tipos de interações
(como gestos de flick, swipe, pinch e drag) vêm sendo absorvidas pelos usuários.
Na linguagem QML alguns componentes já implementam algum tipo de interação,
como é o caso dos elementos a seguir: ListView, GridView e PathView, que permitem
fazer o scroll por seus elementos; TextInput e TextEdit, que possibilitam a inserção e edição de texto; Flickable e PinchArea, que lidam com a interação através de gestos de flick
e pinch; Flipable e MouseArea, que tratam dos eventos de mouse; e finalmente Keys e
FocusScope, referentes aos eventos de teclado. Nas seções a seguir, serão apresentados
os tipos de interação mais básicos que podem ser implementados com a linguagem QML:
eventos de clique (MouseArea) e entrada de texto (TextInput).
9.3.2.1. MouseArea
O MouseArea trata-se de um elemento para o tratamento de eventos de clique. Ele
possui todos os sinais e slots necessários para a construção de qualquer funcionalidade
baseada em eventos de mouse. O MouseArea é um elemento invisível e sua utilização é,
tipicamente, associada a um elemento visível.
O elemento MouseArea permite capturar uma variedade de eventos através de
seus slots. Os slots apresentados na Tabela 9.3 são os mais comuns em dispositivos móveis
e podem ser amplamente utilizados no tratamento de eventos em aparelhos que possuem
tela de toque. O exemplo exibido na Listagem 9.8 apresenta o código para o tratamento
de eventos de clique (onClicked) e pressionamento e liberação (onPressAndHold) em
201
aplicativos que possuam tela de toque. O slot chamado para cada sinal escreve o tipo
de evento no console do aplicativo. Os outros eventos apresentados na Tabela 9.3 são
tratados de maneira semelhante.
Slot
onCanceled
onClicked
onDoubleClicked
onPressAndHold
onPressed
onReleased
Descrição
Chamado quando um evento de mouse é cancelado, seja porque
o evento não foi aceito ou porque foi interceptado por outro elemento.
Chamado quando ocorre um clique, ou seja, um pressionamento
seguido de liberação.
Chamado quando ocorre um duplo clique, ou seja, um pressionamento seguido de uma liberação seguida de outro pressionamento.
Esse slot é chamado quando existe um longo pressionamento (durante 800ms).
O slot é chamado quando ocorre um pressionamento.
Chamado quando ocorre uma liberação do ponteiro.
Tabela 9.3. Principais slots associados aos eventos do elemento MouseArea.
1 import QtQuick 1.0
2
3 Item {
4
width: 360
5
height: 640
6
7
MouseArea {
8
anchors.fill: parent
9
onClicked: console.log("Evento: click")
10
onPressAndHold: {
11
console.log("Evento: Press and hold")
12
}
13
}
14 }
Listagem 9.8. Tratamento de eventos de mouse com os slots onClicked e onPressAndHold.
Outra funcionalidade muito interessante proporcionada pelo MouseArea é o drag.
Através do drag, o usuário pode arrastar elementos na tela. Esse evento é muito utilizado
em dock widgets4 e jogos. O exemplo exibido na Listagem 9.9 ilustra como o evento de
drag pode ser alcançado facilmente usando o elemento MouseArea.
É importante observar que o layout baseado em pontos de ancoragem pode comprometer o tratamento de eventos de drag. Dependendo do tipo de ancoragem utilizado, o
objeto pode ficar totalmente ancorado, impedindo sua movimentação na tela do aplicativo.
4 Dock
widgets é um painel de ícones que inicialmente aparece escondida nas bordas da tela de um
aplicativo. Ao clicar e arrastar a dock widgets, o painel com os ícones é exibido, permitindo assim que esses
ícones sejam clicados.
202
1 import QtQuick 1.0
2
3 Rectangle {
4
id: background
5
color: "lightblue"
6
width: 360
7
height: 640
8
...
9
Rectangle {
10
id: dragable
11
color: "white"
12
width: 50
13
height: 50
14
...
15
MouseArea {
16
anchors.fill: parent
17
drag.target: dragable
18
}
19
}
20 }
Listagem 9.9. Exemplo de implementação de um evento de drag.
9.3.2.2. Entrada de Dados
Na linguagem QML, os elementos disponíveis para realizar entrada de dados são TextInput e TextEdit. Ambos são utilizados para entrada de texto, porém o TextInput mostra
uma única linha de texto editável não formatado, enquanto o TextEdit exibe várias linhas
de texto editável e formatado.
O texto digitado no elemento TextInput pode ser restringido através da utilização
da propriedade validator ou inputMask. Utilizando as restrições de entrada, o elemento
TextInput somente aceitará o texto que esteja em um estado aceitável ou, no mínimo,
intermediário. Alguns validadores suportados são IntValidator, DoubleValidator e RegExpValidator.
A Listagem 9.10 apresenta um trecho de código demonstrando a utilização da
propriedade validator para a validação de texto. Nesse exemplo, a propriedade utiliza
o tipo DoubleValidator com as seguintes propriedades: bottom (menor valor assumido
pelo campo), top (maior valor assumido pelo campo) e decimals (número máximo de
dígitos após o ponto decimal). O slot onTextChanged verifica o valor da propriedade
acceptableInput e modifica a cor de fundo do campo de entrada para verde claro quando
o texto for válido ou para vermelho claro, caso contrário.
Outra possibilidade interessante do elemento TextInput é a utilização da propriedade echoMode, que especifica como o texto deve ser apresentado. Essa propriedade pode assumir as seguintes opções: TextInput.Normal (exibição normal), TextInput.Password (exibe asteriscos e é normalmente utilizado para exibição de senhas), TextInput.NoEcho (não exibe o texto) e TextInput.PasswordEchoOnEdit (com exceção do
caractere atual, todos os outros são exibidos como asterisco).
203
1 import QtQuick 1.0
2
3 Rectangle {
4
id: background
5
width: 200
6
height: 70
7
TextInput {
8
focus: true; horizontalAlignment: TextInput.AlignHCenter
9
font {family: "Helvetica"; pointSize: 20}
10
anchors { fill: parent; topMargin: 20 }
11
validator: DoubleValidator {
12
bottom: 0.0; top: 99.99; decimals: 2
13
}
14
onTextChanged: {
15
if (acceptableInput) {
16
background.color = "lightgreen"
17
} else {
18
background.color = "indianred"
19
}
20
}
21
}
22 }
Listagem 9.10. Exemplo do uso da propriedade validator no elemento TextInput.
9.4. Criando Animações com Estados e Transições
As propriedades de objetos QML podem ser manipuladas através de código JavaScript,
permitindo assim que animações sejam criadas de maneira imperativa. A criação de animações através de código JavaScript é muitas vezes uma tarefa complexa para os programadores. QML disponibiliza um conjunto de elementos baseados em estados e transições,
que quando associados a outros elementos, facilitam a criação de animações nas aplicações. As seções a seguir apresentam os conceitos e elementos relacionados a estados,
transições e animações em QML.
9.4.1. Estados em QML
Em QML, estados são coleções de configurações definidas através do elemento State.
Um objeto alcança um estado quando as mudanças realizadas nas suas propriedades representam um dos estados presentes em sua coleção de estados. A propriedade states
armazena essa coleção (representado através de uma lista de objetos do tipo State) e
representa todos os estados possíveis de um objeto.
A simples declaração de um elemento automaticamente cria um estado padrão,
chamado de estado base, definido como “” (string vazia). Esse é o estado em que um objeto se encontra quando não representa nenhum dos estados definidos em sua propriedade
states. Outros estados podem ser declarados e a transição entre esses estados pode ser realizada facilmente modificando o valor da propriedade state (no singular), que armazena
o estado atual de um objeto. O valor dessa propriedade pode ser modificado diretamente
em um slot ou função escrita em JavaScript, como apresentado na Listagem 9.11.
O elemento State possui as seguintes propriedades: changes (lista de mudanças
204
1 onClicked: {
2
if(obj.state == "clicado") {
3
obj.state = "";
4
}
5
else {
6
obj.state = "clicado";
7
}
8 }
Listagem 9.11. Exemplo da alteração do estado de um objeto utilizando código JavaScript
diretamente.
a serem realizadas neste estado), extend (nome do estado pai), name (nome do estado)
e when (condição para ativação do estado). A Listagem 9.12 apresenta um exemplo da
utilização da propriedade when para a ativação do estado “clicado” do objeto rect. Nesse
caso, a propriedade diz que esse estado só será ativado quando o objeto representado pelo
MouseArea for clicado, ou seja, quando o sinal clicked do objeto mouse for emitido.
Na linha 12 da Listagem 9.12 também é possível observar a utilização do elemento
PropertyChanges. Esse elemento é utilizado para modificar as propriedades de um objeto específico identificado em target durante o tempo em que um estado estiver ativado.
Então, nesse exemplo, a propriedade color do objeto rect (target) é alterada para “red”
enquanto esse objeto estiver no estado “clicado”.
1 import QtQuick 1.0
2
3 Rectangle {
4
id: rect; color: "green"; width: 120; height: 120
5
MouseArea { id: mouse; anchors.fill: parent }
6
states: [
7
State {
8
name: "pressed"
9
when: mouse.pressed
10
PropertyChanges { target: rect; color: "red" }
11
}
12
]
13 }
Listagem 9.12. Utilização da propriedade when do elemento State para modificação de
estado de um objeto.
9.4.2. Animação com com elemento Behavior
Em QML, a transição de um estado para outro ocorre de maneira brusca e como consequência os valores das propriedades também são alterados bruscamente. Porém, muitas
vezes, o esperado é que a transição ocorra de maneira suave, ou seja, através de animações, que são criadas através da interpolação entre os valores inicial e final de uma
propriedade.
O elemento Behavior é utilizado com o propósito de se criar animações em QML.
Esse elemento define uma animação padrão que deve ser utilizada sempre que uma de-
205
terminada propriedade de um objeto sofrer alterações. Uma boa prática de programação
para esse elemento é utilizar estados bem definidos para realizar as transições, ou seja,
evitar a utilização do estado base (“”). Essa prática é recomendada porque se uma animação for interrompida, o estado base assume os valores intermediários das propriedades e
o comportamento final pode não ser o esperado.
A Listagem 9.13 apresenta um exemplo da utilização do elemento Behavior.
Nesse exemplo, foram declarados dois estados no objeto rect, denominados “EstadoIncial” e “EstadoFinal”. A propriedade x possui o valor 0 no primeiro estado e o valor 400
no segundo estado. A declaração Behavior on x é responsável por realizar a interpolação
dos valores dessa propriedade entre os dois estados que foram declarados. A interpolação
é do tipo NumberAnimation e deve ter uma duração de 200ms.
Além do tipo NumberAnimation existem outras animações baseadas nos tipos
de dados. Algumas das animações mais utilizadas são: ColorAnimation, para animar
mudanças nos valores de cor; RotationAnimation, para animar rotações; e PropertyAnimation, para animar mudanças nos valores de propriedades.
1 import QtQuick 1.0
2
3 Rectangle {
4
width: 500; height: 100
5
MouseArea { id: mouse; anchors.fill: parent }
6
Rectangle {
7
id: rect; width: 100; height: 100; color: "blue"
8
Behavior on x { NumberAnimation{duration: 200} }
9
states: [
10
State {
11
name: "EstadoInicial"
12
when: !mouse.pressed
13
PropertyChanges { target: rect; x: 0 }
14
},
15
State {
16
name: "EstadoFinal"
17
when: mouse.pressed
18
PropertyChanges { target: rect; x: 400 }
19
}
20
]
21
}
22 }
Listagem 9.13. Exemplo de animação utilizando o elemento Behavior.
Uma propriedade pode ter somente um elemento Behavior associado à ela. Para
realizar múltiplas transições com diferentes propriedades é necessário utilizar os elementos ParallelAnimation ou SequentialAnimation, para animações paralelas ou sequenciais, respectivamente.
9.4.3. Transições entre estados
Outra forma de se fazer animações em transições entre estados é utilizando o elemento
Transition. Esse elemento define as animações que devem acontecer quando ocorrem
206
trocas de estados. As transições são atribuídas a um objeto através da propriedade transitions, que pode receber um único objeto ou uma lista de objetos do tipo Transition.
O elemento Transition possui 4 propriedades: animation, que é um lista de animações que devem ser executadas durante a transição; from e to, indicam que a transição é
aplicável somente quando ocorrer a mudança de estados especificada nessas propriedades;
e reversible, que indica se a animação da transição deve ser automaticamente revertida
quando as condições de ativação forem invertidas. Essa última propriedade evita a criação
de uma nova transição para realizar a animação reversa quando as condições de ativação
estiverem invertidas.
As transições podem conter elementos de animação para interpolar as mudanças
causadas por mudanças de estados nos valores das propriedades. Os elementos utilizados
podem ser os mesmos utilizados com o elemento Behavior apresentado na Seção 9.4.2.
Porém, se uma mudança de estado altera uma propriedade que foi declarada tanto em um
Transition quanto em um Behavior, o comportamento definido no elemento Transition
sobrepõe o elemento Behavior.
A Listagem 9.14 apresenta um exemplo da utilização do elemento Transition para
realizar animações. Nesse exemplo, o elemento define animações para as propriedades
color e x do objeto obj utilizando os elementos de animação ColorAnimation e NumberAnimation, respectivamente.
1 import QtQuick 1.0
2
3 Rectangle {
4
width: 200; height: 100
5
Rectangle { id: obj; width: 100; height: 100; color: "red" }
6
MouseArea { id: mouse; anchors.fill: parent }
7
states: State {
8
name: "EstadoFinal";
9
when: mouse.pressed
10
PropertyChanges { target: obj; x: 100; color: "green" }
11
}
12
transitions: Transition {
13
NumberAnimation { properties: "x"; duration: 200 }
14
ColorAnimation { duration: 200 }
15
}
16 }
Listagem 9.14. Exemplo da utilização do elemento Transition para realizar animações.
9.5. Componentes QML Customizados
A linguagem QML é fortemente baseada nos conceitos de componentização. Dessa maneira, qualquer trecho de código pode ser tornar um componente e a própria declaração
de elementos pode ser vista como o uso de componentes pré-definidos.
9.5.1. Definição de Componentes
Um componente QML é como uma caixa preta que interage com o mundo externo através de suas propriedades, sinais e funções, e geralmente é definido dentro de um arquivo
207
QML. Um ponto importante a ser considerado é que arquivos QML que definem componentes deve ter seus nomes iniciados com letra maiúscula. A Listagem 9.15 apresenta
um exemplo de um componente Button, definido em um arquivo Button.qml, que emite
sinais à medida que recebe cliques do usuário.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Arquivo: Button.qml
import QtQuick 1.0
Rectangle {
id: button
anchors.centerIn: parent
width: 100; height: 100
radius: 50; color: ’red’
signal clicked
MouseArea {
anchors.fill: button
onClicked: {
button.clicked()
}
}
}
Listagem 9.15. Componente customizado criado com o nome de arquivo Button.qml.
Componentes em QML também podem ser criados de uma maneira mais explícita
usando o elemento Component, que permite uma definição inline, ou seja, dentro de um
documento QML, ao invés de um arquivo separado. A vantagem do uso desse elemento é
permitir reusar pequenas definições de componente dentro de um arquivo QML, ou para
definir componentes que pertencem logicamente a um mesmo arquivo QML. Assim, o
elemento Component gera componentes abstratos que servem como um modelo para
reproduzir e renderizar cópias do componente definido. É importante esclarecer que o
elemento Component apenas atua na definição de componentes e essa definição pode
ser utilizada por outros elementos e métodos, tais como:
• Loader. É um elemento usado para carregar componentes QML visuais dinamicamente. Através dele é possível especificar como fonte de referência tanto um
arquivo QML, usando a propriedade source, quanto um objeto Component, este
último utilizando a propriedade sourceComponent;
• createObject. É um método pertencente aos objetos do tipo Component, que
permite criar dinamicamente objetos a partir de suas definições de componente.
Este método recebe como parâmetro a referência (id) do objeto que será o pai do
novo objeto criado.
A Listagem 9.16 apresenta um exemplo da definição de um componente como
um círculo de cor verde com id igual a circleComponent. Nesse exemplo, o elemento
Loader é declarado, especificando o objeto circleComponent como sendo o componente
de referência, através da propriedade sourceComponent, e então um círculo verde é
renderizado na tela do dispositivo na posição padrão (x = 0 e y = 0).
208
O mesmo exemplo mostra a declaração de um elemento MouseArea, onde é declarado um slot onMousePositionChanged que é chamado no momento em que ocorre
uma mudança no ponto de clique na tela, ou seja, no momento em que a área de toque é
arrastada. Nesse slot é listada uma sequência de comandos visando a criação de objetos
dinamicamente segundo a definição feita no componente circleComponent. A cada vez
que o slot onMousePositionChanged é chamado, o método createObject() de circleComponent cria um novo objeto do mesmo tipo dentro do objeto mainView. Quando
ocorre a criação do círculo dentro do slot, algumas das suas propriedades são alteradas
diretamente no objeto armazenado na variável JavaScript circle. Assim, o novo círculo
passa a ter seu centro no posição atual do mouse, e sua cor passa a ser azul.
1 import QtQuick 1.0
2
3 Item {
4
id: mainView; width: 360; height: 640
5
Component {
6
id: circleComponent
7
Rectangle {
8
id: circle
9
width: 40; height: 40; radius: 40; color: "green"
10
}
11
}
12
Loader { id: pointer; sourceComponent: circleComponent}
13
MouseArea {
14
anchors.fill: mainView
15
onMousePositionChanged: {
16
var circle = circleComponent.createObject(mainView)
17
circle.x = mouseX - circle.width/2
18
circle.y = mouseY - circle.height/2
19
circle.color = ’blue’
20
}
21
}
22 }
Listagem 9.16. Definição e carregamento de um componente para desenhar um círculo.
9.5.2. Criação Dinâmica de Componentes com JavaScript
A utilização de código JavaScript é outra maneira de especificar os componentes. Essa
abordagem bastante usada no desenvolvidos de jogos em QML, onde é preciso criar um
número grande de objetos referentes à cena de jogo e fazer o gerenciamento destes à
medida em que ocorrem alterações no estado do jogo.
Para definir componentes dentro de um trecho de código JavaScript é utilizada
a função createComponent() pertencente a variável global Qt. Esta função requisita
como parâmetro a url do arquivo QML onde o componente foi declarado e retorna um
objeto do tipo Component.
A criação de objetos a partir de componentes que foram definidos é possível por
meio do método createObject(). Esta função pertence a objetos do tipo Component, e
recebe como parâmetros a referência do item que será o pai do novo objeto e um valor do
tipo dicionário, uma série de pares chave-valor com as configurações das propriedades. O
209
retorno desta função é um objeto definido da forma como é declarado no Component e
com suas propriedades alteradas segundos os valores passados como argumento. Assim é
possível criar diferentes objetos de uma definição de componente e customizar livremente
seus valores de propriedades.
O código apresentado na Listagem 9.17 demonstra a criação de um componente
do tipo Button, mostrando que o objeto criado segue a mesma interface definida na declaração inicial do componente. Um objeto do tipo Button é criado de maneira dinâmica
através do método createComponent() e é armazenado na variável buttonComponent.
A variável buttonObj, por sua vez, recebe um objeto Button após a chamada do método
createObject() do objeto buttonComponent, conforme apresentado na linha 14.
1 import QtQuick 1.0
2
3 Rectangle {
4
id: mainView
5
width: 360
6
height: 640
7
8
function randomColor() {
9
return Qt.rgba(Math.random(),
10
Math.random(),
11
Math.random(),
12
0.5 + (Math.random())/2)
13
}
14
15
Component.onCompleted: {
16
var buttonComponent = Qt.createComponent("Button.qml");
17
var buttonObj = buttonComponent.createObject(
18
mainView,
19
{"color" : randomColor()});
20
buttonObj.clicked.connect(function() {
21
color = randomColor()
22
});
23
}
24 }
Listagem 9.17. Criação de componentes utilizando código JavaScript.
Tanto as propriedades quando os sinais fazem parte da interface de um componente QML, assim todos os objetos criados a partir de um componente possuem as mesmas definições de propriedades e sinais. Logo, ainda na Listagem 9.17, é possível conectar um slot ao sinal clicked do objeto buttonObj do tipo Button (linha 16), onde tal
sinal foi definido. O papel do slot conectado ao sinal clicked é atribuir um valor de cor
aleatório a propriedade color à tela de fundo do aplicativo. É interessante perceber que
apesar de estar dentro de um slot do objeto do tipo Button, o escopo de propriedade pertence a mainView, dado que o Component.onCompleted é declarado em mainView.
Decorre então que a propriedade color refere-se ao objeto mainView e não ao próprio
Button. Como resultado, tem-se um botão centralizado no objeto pai, mainView, e que
ao ser pressionado altera a cor de fundo da tela.
210
9.5.2.1. Criação de Objetos a partir de uma String
Uma maneira interessante de criação de objetos QML em tempo de execução é a partir
de uma string utilizando código JavaScript. Esses objetos são criados através do método
createQmlObject() disponível na variável global Qt, conforme apresentado na Listagem 9.18.
1 var newObj = Qt.createQmlObject(
2
’import QtQuick 1.0;’ +
3
’Rectangle { color: "red"; width: 20; height: 20}’,
4
parentItem,
5
"dynamicSnippet1");
Listagem 9.18. Novo objeto criado a partir de uma string utilizando código JavaScript
O primeiro argumento do método define o componente, utilizando o código com
os mesmos elementos de declarações em arquivos QML. Se o código definido na string
possuir algum caminho de arquivo, este deve ser relativo ao item pai do objeto criado.
O segundo argumento é o item pai do objeto a ser criado. Por fim, o terceiro argumento
é apenas um nome de diretório associado ao novo objeto, caso seja necessário reportar
erros.
9.5.2.2. Deletando Objetos Dinamicamente
De maneira geral, uma grande quantidade de itens criados dinamicamente poder trazer
impactos negativos ao desempenho de um aplicativo. Assim, é altamente recomendável
que se tenha um bom gerenciamento dos objetos criados. Deletar os objetos criados
dinamicamente à medida que se tornarem desnecessários pode beneficiar o desempenho
como um todo.
É importante pontuar a diferença entre itens criados dinamicamente por funções
JavaScript e aqueles criados por elementos QML, tais como o Loader. Estes últimos possuem em sua implementação o pressuposto de que seus itens gerados não serão deletados
durante o tempo de vida do componente que os engloba. Assim deve ser evitado deletar
qualquer item que não tenha sido diretamente criado por funções JavaScript.
Todo item possui um método de destruição chamado destroy(). Este método possui um argumento opcional onde pode ser passado o tempo em milissegundos antes que o
objeto seja destruído. A Listagem 9.19 apresenta um exemplo de criação dinâmica através
de uma string e destruição do objeto criado. O trecho de código definido no slot onCompleted é executado no momento em que o item pai mainView é carregado e renderizado
na tela. Então, um novo objeto é criado (um retângulo vermelho de bordas arredondadas)
cujo pai é definido como sendo o mainView e seu caminho para relatórios de erros como
“snippetCode1”. A variável newObject passa a armazenar o objeto retângulo, enquanto
na linha seguinte uma variável newMouseArea recebe uma instância do tipo MouseArea. Ao final do exemplo, um slot é conectado ao sinal clicked do MouseArea, onde o
primeiro objeto tem sua opacidade modificada para zero e então seu método de destruição
é chamado.
211
1 import QtQuick 1.0
2
3 Rectangle {
4
id: mainView; width: 640; height: 360
5
Component.onCompleted: {
6
var newObject = Qt.createQmlObject(
7
" import QtQuick 1.0; " +
8
" Rectangle { anchors.centerIn: parent; " +
9
"
color: ’red’; width: 200; height: 200; " +
10
"
radius: 20}",
11
mainView, "snippetCode1");
12
var newMouseArea = Qt.createQmlObject(
13
" import QtQuick 1.0; " +
14
" MouseArea { anchors.fill: parent;}",
15
newObject, "mouseArea1");
16
newMouseArea.clicked.connect(function() {
17
newObject.opacity = 0;
18
newObject.destroy(1000)
19
});
20
}
21 }
Listagem 9.19. Exemplo da utilização do método destroy() para a destruição de objetos
criados dinamicamente.
9.5.3. Definição de Componentes utilizando Qt/C++
A grande diversidade de elementos QML permitem criar variados tipos de interface de
maneira declarativa. Entretanto para aplicações que exijam renderizações de forma geométricas complexas ou possuam comportamento funcional acima do disponibilizado pelos elementos QML padrões, existe a possibilidade de estender novas funcionalidade através de classes C++. Dessa maneira, elementos QML com alto grau de customização podem ser definidos em uma classe C++ que herde o QDeclarativeItem, a classe pai de
todos os itens declarativos.
Feita a sobrecarga do método de paint do QDeclarativeItem, é possível criar um
componente QML utilizando todas as potencialidades oferecidas pelo framework Qt. Na
Listagem 9.20, um triângulo é desenhado através de um caminho de pontos pré-definidos,
um QPaintPath. O painter é configurado para realizar a renderização do caminho de
pontos definido, através do método drawPath do QPainter. Os métodos setPen e setBrush apenas selecionam a cor preta para os traços do desenho e uma cor pré-definida
m_color para o preenchimento da figura.
9.5.3.1. Criação de Novos Tipos
Uma vez que um novo elemento QML é criado em C++, é necessário registrá-lo para uso
dentro de arquivos QML, ou seja, é preciso certificar que a máquina de execução QML
consiga compreender o significado dos novos símbolos definidos.
Especificada no cabeçalho qdeclarativeengine.h, a função qmlRegisterType re-
212
1 class MyItem : public QDeclarativeItem
2 {
3
...
4
void paint(QPainter *painter,
5
const QStyleOptionGraphicsItem *,
6
QWidget *) {
7
QPainterPath path;
8
path.moveTo(boundingRect().width()/2,0);
9
path.lineTo(boundingRect().width(),boundingRect().height());
10
path.lineTo(0,boundingRect().height());
11
path.lineTo(boundingRect().width()/2,0);
12
13
painter->setPen(QColor("black"));
14
painter->setBrush(QBrush(m_color));
15
painter->drawPath(path);
16
}
17 };
Listagem 9.20. Definição de um novo componente utilizando código Qt/C++.
gistra os tipos C++ no sistema QML, através da especificação de um URI (Uniform Resource Identifier) da biblioteca, um número de versão e o nome do componente. Abaixo
segue um exemplo de seu uso dentro do código C++, onde o elemento MyItem é declarado através do registro da classe MyItem dentro da biblioteca MyComponents sob a
versão 1.0.
qmlRegisterType<MyItem>("MyComponents", 1, 0, "MyItem");
O item customizado pode ser facilmente importado para o código QML, sendo que
para isso é necessário conhecer o nome e versão da biblioteca onde está agrupado, assim
como seu nome de componente. Uma vez importado, o novo elemento segue exatamente
as mesmas regras de qualquer outro elemento do tipo Item, possuindo assim também
suas propriedades, tais como x, y, width, height e outras. A Listagem 9.21 apresenta um
exemplo da utilização do elemento do novo tipo (MyItem) criado a partir de código C++.
1 import MyComponents 1.0
2
3 Rectangle {
4
MyItem {
5
id: myItem
6
}
7 }
Listagem 9.21. Declaração do novo elemento criado a partir de código C++.
9.6. Plataformas de Desenvolvimento
No contexto de dispositivos móveis, Symbian e Maemo/MeeGo são algumas plataformas
que oferecem suporte ao desenvolvimento de aplicações em Qt. No desenvolvimento em
Qt, geralmente não são necessárias muitas modificações no código para que um projeto
213
existente funcione em uma nova plataforma. Dessa maneira, na maioria dos casos o
processo de compilar o código para essa nova plataforma e executar a aplicação funciona
sem maiores problemas. Porém, algumas vezes é necessário realizar configurações de
projeto no arquivo .pro para que o aplicativo tenha acesso aos recursos do dispositivo.
A Listagem 9.22 apresenta algumas configurações específicas da plataforma Symbian utilizadas no desenvolvimento de aplicações. As duas instruções apresentadas nessa
listagem são: TARGET.CAPABILITIES, que define privilégios extras para que a aplicação tenha acesso aos recursos do dispositivo, como é o caso dos serviços de rede com
NetworkServices; e TARGET.EPOCHEAPSIZE, que define a quantidade mínima e
máxima de memória disponível para a aplicação.
1 symbian: {
2
...
3
TARGET.CAPABILITY += NetworkServices
4
TARGET.EPOCHEAPSIZE = 0x020000 0x4000000
5
...
6 }
Listagem 9.22. Configurações específicas da plataforma Symbian para desenvolvimento Qt.
Na plataforma Maemo/MeeGo, a IDE Qt Creator cria os projetos com todos os
recursos necessários para o desenvolvimento. No caso da plataforma Android, ainda não
existe um port oficial, mas já existem algumas iniciativas para utilizar desenvolver com
o Framework Qt nessa plataforma. O Necessitas [3] é um projeto que tem o objetivo de
prover o port do Qt para a plataforma Android e integração com o Qt Creator. O site do
projeto fornece as informações necessárias para começar a utilizar o Necessitas SDK.
Quanto ao processo de compilação das aplicações para instalação no dispositivo
móvel, o QtSDK fornece o módulo Remote Compiler. Esse módulo foi criado para contornar a ausência de soluções que permitissem a compilação dos binários Symbian nas
plataformas Linux e Apple Mac. Esse recurso permite a compilação para as plataformas
Symbian S60, Symbianˆ1, Symbianˆ3, Maemo 5 e MeeGo 1.2 Harmattan, oferecendo
suporte para a versão 4.6 do Qt, incluindo o Qt Quick a partir da versão 4.7 do Qt.
9.7. Considerações Finais
Os elementos e características da linguagem QML apresentados neste capítulo possibilitam o desenvolvimento cross-platform de UIs de alto nível de maneira rápida e intuitiva. Para reforçar a importância desse kit de desenvolvimento, o framework Qt vem
sendo utilizado por grandes empresas em projetos como Google Earth, Skype, KDE e
Opera [7]. O Ambiente declarativo Qt Quick, através da linguagem QML, surge como
uma ferramenta promissora para a criação de UIs onde a rapidez de desenvolvimento e
a experiência do usuário são cruciais para as aplicações. Além disso, novos dispositivos
móveis recentemente lançados com o sistema operacional MeeGo possuem o Qt como kit
de desenvolvimento padrão.
Em resumo, neste capítulo foi apresentado como utilizar a linguagem QML no ambiente declarativo Qt Quick para a criação de interfaces para dispositivos móveis. Através
de elementos básicos como Rectangle, Item, MouseArea, Text e Image foi apresen-
214
tado como especificar UIs pelo seu conteúdo, e não por meio de comandos imperativos
em Qt/C++ na especificação dos métodos. Além disso, outras características importantes da linguagem QML (como a criação de animações e o tratamento de eventos) foram
apresentadas, possibilitando a criação de UIs modernas e flexíveis.
9.8. Agradecimentos
A escrita deste capítulo foi apoiada pelo CETELI (Centro de Pesquisa e Desenvolvimento
em Tecnologia Eletrônica e da Informação) e pelo INdT (Instituto Nokia de Tecnologia).
Referências
[1] Goderis, S. (2005) “High-level declarative user interfaces”. In: Companion to the
20th annual ACM SIGPLAN conference on Object-oriented programming, systems, languages, and applications (OOPSLA ’05). New York, NY, USA, ACM,
p. 236-237.
[2] QUIt Coding, Crash course to Qt Quick Game Programming, disponível
em:
http://quitcoding.com/download/Qt_Quick_Game_Programming_1_0.pdf,
acessado em outubro de 2011.
[3] Necessitas, disponível em: http://sourceforge.net/p/necessitas/home/necessitas/,
acessado em outubro de 2011.
[4] Nokia, QML Elements, disponível em:
http://doc.qt.nokia.com/4.7snapshot/qdeclarativeelements.html, acessado em outubro de 2011.
[5] Nokia, Qt - Cross-platform application and UI framework, disponível em:
http://qt.nokia.com/, acessado em outubro de 2011.
[6] Nokia, Qt 4.7: QML Viewer, disponível em: http://doc.qt.nokia.com/4.7snapshot/qmlviewer.html, acessado em outubro de 2011.
[7] Nokia, Qt in Use, disponível em: http://qt.nokia.com/qt-in-use/, acessado em outubro de 2011.
[8] Nokia, Qt Quick, http://qt.nokia.com/qtquick/, acessado em outubro de 2011.
[9] Vision
Mobile,
Developer
Economics
2011,
Disponível
http://www.visionmobile.com/devecon.php, acessado em outubro de 2011.
em:
[10] Vision Mobile, Mobile Economics Developer 2010 and Beyond, Disponível em:
http://www.visionmobile.com/rsc/researchreports/Mobile%20Developer %20Economics%202010%20Report%20FINAL.pdf, acessado em outubro de 2011.
[11] W3C Recommendation, Basic Data Types and Interfaces, disponível em:
http://www.w3.org/TR/SVG/types.html#ColorKeywords, acessado em outubro de
2011.
[12] Zucker, D. e Rischpater, R., Beginning Nokia Apps Development: Qt and HTML5
for Symbian and MeeGo, Apress Series. Apress, 2010.
215
Capítulo
10
Técnicas de Processamento de Imagens em Diagnóstico Auxiliado por Computador
Rodrigo M. S. Veras, Iális C. Paula Jr. e Fátima N. S. Medeiros
Abstract
Computer-aided diagnosis systems (CAD) are defined to improve the accuracy of diagnosis by health experts, as well as consistency of interpretation of imaging tests by using the
computer’s response as a reference. Large collections of medical imaging have brought
the necessity of using computational techniques to process analyze and retrieve pictorial
information related to them. Therefore, computer-aided diagnosis has been attracting
great interest. The aim of this chapter is to introduce the main concepts related to CAD
systems: kinds of CAD and major areas of activity, techniques of Digital Image Processing, Pattern Recognition algorithms and practical applications.
Resumo
Sistemas de Diagnóstico Auxiliado por Computador (CAD - Computer-aided diagnosis)
são definidos para aprimorar a acurácia do diagnóstico realizado por especialistas de
saúde, assim como a consistência da interpretação de exames de imagens, mediante o
uso da resposta do computador como referência. Grandes coleções de imagens médicas trouxeram consigo a necessidade de utilizar técnicas computacionais para processar,
analisar e recuperar a informação pictórica relacionada às mesmas. Dessa forma, o
diagnóstico auxiliado por computador vem atraindo grande interesse. O objetivo deste
capítulo é apresentar os principais conceitos ligados aos sistemas CAD: tipos de CAD e
principais áreas de atuação, técnicas de Processamento Digital de Imagens, algoritmos
de Reconhecimento de Padrões e aplicações práticas.
10.1. Introdução
A demanda crescente dos hospitais por um diagnóstico de exames baseados em imagens
de forma rápida e precisa, somada aos avanços computacionais e de processamento de
216
imagens, fizeram surgir novas frentes de pesquisa relacionadas ao diagnóstico médico auxiliado por computador [Marques 2001]. Diagnóstico auxiliado por computador, também
conhecido pela sigla CAD (Computer-Aided Diagnosis) é definido como um diagnóstico
realizado pelo especialista, utilizando o resultado de análises quantitativas automatizadas
de imagens como auxílio para tomada de decisões diagnósticas. A finalidade do diagnóstico auxiliado por computador é melhorar a acuidade do diagnóstico, assim como a consistência da interpretação da imagem, mediante o uso da resposta do computador como
referência. A ideia do CAD pode ser aplicada em todas as modalidades de obtenção de
imagem, incluindo a radiografia convencional, tomografia computadorizada, ressonância
magnética, ultra-sonografia e medicina nuclear.
Podem-se desenvolver sistemas CAD para todos os tipos de exame de todas as
partes do corpo, incluindo, o crânio, tórax, abdome, estrutura óssea, sistema vascular e
outros. O objetivo deste capítulo é apresentar os principais conceitos ligados aos sistemas
CAD: tipos de CAD e principais áreas de atuação, técnicas de Processamento Digital de
Imagens, algoritmos de Reconhecimento de Padrões e aplicações práticas.
10.2. Diagnóstico Auxiliado por Computador
Diagnóstico auxiliado por computador pode ser definido como um diagnóstico feito por
um médico que utiliza o resultado de análises quantitativas automatizadas de imagens
como uma “segunda opinião” para a tomada de decisões diagnósticas [Doi 2007]. É importante ressaltar que o computador é utilizado somente como uma ferramenta para obtenção de informação adicional, sendo o diagnóstico final sempre feito pelo especialista,
o que diferencia claramente o conceito básico de CAD do conceito de “diagnóstico automatizado”, que foi um conceito proposto e estudado nas décadas de 60 e 70 [Doi 2007].
A finalidade do CAD é melhorar a acurácia do diagnóstico, assim como a consistência da interpretação da imagem, mediante o uso da resposta do computador como referência. A resposta do computador pode ser útil, uma vez que o diagnóstico do especialista
é baseado em avaliação subjetiva, estando sujeito a variações intra e interpessoais, bem
como perda de informação devido à baixa qualidade da imagem, sobreposição de estruturas, fadiga visual ou distração. Além disso, foi demonstrado que uma dupla leitura (por
dois especialistas) pode aumentar a sensibilidade do diagnóstico[Thurfjell et al. 1994]. A
proposta do CAD é funcionar como um segundo especialista.
Basicamente, existem dois tipos de aplicações de sistemas CAD. Um é o auxílio
à detecção de lesões, a partir da localização de padrões anormais através da varredura da
imagem pelo computador (por exemplo, agrupamentos de microcalcificações em imagens
mamográficas ou nódulos pulmonares em imagens de tórax). O outro é o auxílio ao diagnóstico, através da quantificação de características da imagem e sua classificação como
correspondendo a padrões normais ou anormais (por exemplo, a associação da quantidade
e forma das microcalcificações presentes em um agrupamento com a malignidade ou não
do tumor, ou a associação da textura dos pulmões com lesões intersticiais em imagens de
tórax).
Em geral, os sistemas CAD utilizam-se de técnicas provenientes de duas áreas
do conhecimento: visão computacional, que envolve o processamento de imagem para
realce, segmentação e extração de atributos, e inteligência artificial, que inclui métodos
217
para seleção de atributos e reconhecimento de padrões.
10.2.1. Auxílio à Detecção
A detecção automatizada de lesões envolve a localização pelo computador de regiões contendo padrões suspeitos, porém com a classificação da lesão sendo feita exclusivamente
pelo especialista. Sistemas para auxílio à detecção têm sido desenvolvidos, principalmente, para imagens radiológicas de tórax e de mama.
10.2.2. Auxílio ao Diagnóstico
Uma vez que um padrão suspeito foi detectado, cabe ao especialista decidir o encaminhamento do caso, ou seja, se é necessária a realização de algum outro exame ou de uma
biópsia, por exemplo. Ou então, se um simples acompanhamento é suficiente e, neste
caso, qual deve ser o intervalo até o próximo exame.
Sistemas de análise computadorizada estão sendo desenvolvidos para auxiliar a
distinção entre lesões e não-lesões e aumentar a sensibilidade e especificidade do diagnóstico. Estes sistemas utilizam atributos extraídos e quantificados de forma automatizada
e também por especialistas.
A vantagem da extração automatizada é a objetividade e reprodutibilidade da medida dos atributos escolhidos. Por outro lado, os especialistas utilizam uma grande quantidade de atributos, os quais são extraídos e interpretados simultânea e instantaneamente.
No caso de exames relacionados a câncer, um dos objetivos dos sistemas de auxílio
à classificação é a redução do número de casos benignos encaminhados para biópsia.
Porém, como o “custo” da perda de uma lesão maligna é muito maior que o de uma
classificação errônea de um caso benigno, os sistemas de auxílio ao diagnóstico devem
ser desenvolvidos com o propósito de aumentar a especificidade, porém sem reduzir a
sensibilidade.
10.2.3. Estratégias dos Sistemas CAD
Em [Hong Shao 2004] são propostas estratégias para diagnóstico de imagens, particularmente, aplicados à análise de patologias nos tecidos do cérebro (edema, tumor, etc.), tais
como:
1. Análise comparativa de imagens do mesmo paciente, obtidas pelo mesmo equipamento, com os mesmos parâmetros de escaneamento, mas em diferentes instantes
de tempo
2. Análise comparativa de imagens do mesmo paciente, obtidas pelo mesmo equipamento, no mesmo instante, mas com parâmetros de escaneamento diferentes. Este
tipo de análise é denominado análise multi-espectral.
3. Análise comparativa de imagens do mesmo paciente, mas obtidas através de diferentes tecnologias de escaneamento, tais como, tomografia computadorizada, ressonância magnética, PET e SPECT.
4. Análise comparativa da imagem do paciente com um padrão obtido de pessoas sau-
218
dáveis, denominado atlas anatômico. Na prática, esta técnica não mostrou muita
eficiência dado sua complexidade e dificuldade de estabelecer um padrão anatômico.
Ainda como técnica de análise comparativa, pode-se acrescentar a técnica de comparação de duas imagens do mesmo paciente, mas obtida em diferentes partes do corpo.
Essa a metodologia desenvolvida para detecção de nódulos em mamogramas, por exemplo, a qual é baseada na simetria de arquitetura entre as mamas esquerda e direita, com as
assimetrias indicando possíveis nódulos, conforme descrito em [F.F. et al. 1991].
10.3. Conhecimentos Envolvidos
Em geral, os sistemas CAD utilizam-se de técnicas provenientes de duas áreas do conhecimento, visando a extração e quantificação de atributos de uma imagem em formato
digital. Neste capítulo direcionamos este estudo com base nas seguintes técnicas:
1. Processamento de Imagens: envolve o processamento de imagem para realce, segmentação e extração de atributos.
2. Reconhecimento de Padrões: inclui métodos para seleção de atributos, estatística e
reconhecimento de padrões.
Utilizam-se técnicas de processamento de imagens para realce e segmentação das
lesões, conforme o tipo do exame. Por exemplo, utilizam-se propriedades de descontinuidade dos níveis de cinza, detecção de contorno, bordas ou segmentação para separação de
regiões que apresentem determinada característica. Após o realce e segmentação, segue
o processamento envolvendo a quantificação de atributos da imagem, como, tamanho,
contraste e forma dos seus objetos constituintes.
A descrição dos atributos da imagem relaciona as características reconhecidas subjetivamente pelos especialistas. De um modo geral, os atributos são quantificados a partir
de propriedades métricas, topológicas e de textura dos objetos.
Após a extração e quantificação dos atributos, utiliza-se o reconhecimento de
padrões para distinção entre padrões normais e anormais. Esta área do conhecimento
abrange técnicas de distribuições de probabilidade de classe, técnicas de análise de discriminante, métodos estatísticos e redes neurais.
10.3.1. Processamento Digital de Imagens
O processamento de imagens abrange uma ampla escala de software, hardware e fundamentos teóricos [Gonzalez e Woods 2007]. Entre estes fundamentos, discutiremos nesta
seção técnicas importantes na caracterização e representação das informações relevantes
de uma imagem ao usuário de sistema CAD.
Esta subseção descreve algumas funções de processamento digital de imagens
abordadas em sistema CAD. Inicialmente discute-se sobre o processo de aquisição de
imagens. A subseção 10.3.1.2 descreve estratégias para adequar a imagem ao processamento em que ela será submetida. Técnicas para separar as regiões de interesse de uma
219
imagem são apresentadas na subseção 10.3.1.3. A subseção 10.3.1.4 expõe métodos para
representação e descrição de formas.
10.3.1.1. Aquisição de Imagens
Considera-se aquisição de uma imagem o processo de conversão de uma cena real tridimensional em uma imagem digital produzida por um ou vários sensores. A aquisição de
imagens requer um sensor para imageamento e capacidade de digitalizar o sinal produzido pelo sensor [Burger e Burge 2009]. Este pode ser caracterizado por um dispositivo
físico que seja sensível a uma banda do espectro eletromagnético (como raios-X, ultravioleta, visível ou banda infravermelha), gerando um sinal elétrico proporcional ao nível de
energia recebida. Por fim, converte-se a saída elétrica deste sensor para a forma digital
num outro dispositivo, conhecido como digitalizador [Azevedo et al. 2007]. Dependendo
do tipo do sensor, o resultado pode variar entre uma imagem bidimensional, uma cena
tridimensional ou ainda uma sequência de imagens.



f (x, y) ≈ 

f (0, 0)
f (1, 0)
..
.
f (0, 1)
f (1, 1)
···
···
f (0, M − 1)
f (1, M − 1)
..
.
f (N − 1, 0) f (N − 1, 1) · · · f (N − 1, M − 1)





(1)
O termo imagem refere-se a uma função de intensidade luminosa bidimensional,
denotada por f (x, y). O valor ou amplitude de f nas coordenadas espaciais (x, y) dá a
intensidade (brilho) da imagem naquele ponto. Para adequar-se a um sistema computacional, a função f (x, y) precisa ser digitalizada tanto espacialmente quanto na amplitude. A digitalização de suas coordenadas espaciais é denominada amostragem da imagem e a digitalização da amplitude é chamada quantização em níveis de cinza. Supondo
que uma imagem contínua f (x, y) é aproximada por amostras igualmente espaçadas, arranjadas na forma de uma matriz NxM (Equação (1)) com cada elemento apresentando
uma quantidade discreta. O lado direito desta equação traz a representação de uma imagem digital [Gomes e Velho 1994]. Cada elemento desta matriz é definido como um elemento da imagem ou pixel (abreviação do termo picture element, elemento da figura)
[Azevedo et al. 2007]. Os valores dos pixels podem indicar, além da intensidade da luz,
uma ou várias faixas de cor (gerando imagens em tons de cinza ou coloridas), mas também podem indicar valores físicos como profundidade e absorção ou reflexão das ondas
eletromagnéticas.
Considerando a Equação (1) uma aproximação de uma imagem contínua, devese avaliar quantas amostras e níveis de cinza são suficientes para esta aproximação. A
resolução desta imagem dependerá destes dois parâmetros. Maiores valores nestes índices
indicam maior aproximação da matriz digitalizada à imagem original. Essa relação pode
ser observada na Figura 10.1(b), que se apresenta diferente da Figura 10.1(a), após ser
reamostrada no plano digital e com uma limitação nos níveis de cinza visíveis. Diferentes
equipamentos podem ser utilizados para a aquisição de imagens, como câmeras CCD (do
inglês Charge-Coupled Device, dispositivo de carga acopladade para vídeo e fotografia),
sistema infravermelho, aparelhos para radiologia que utilizam sinais recebidos de raio-X,
220
tomografia computadorizada, medicina nuclear, ultra-sonografia e ressonância magnética
nuclear.
(a)
(b)
Figura 10.1. Efeito da discretização da imagem: exemplo de (a) imagem contínua
e (b) resultado da amostragem e quantização da mesma. Adaptado de Gonzalez
& Woods (2007).
Para a realização de testes em um sistema CAD, é possível processar imagens
armazenadas em repositórios disponíveis na web. Alguns destes podem ser abertos e
oferecem a caracterização das imagens oferecidas. Como exemplo, num sistema CAD
que atue com imagens de mamografia, há bases de dados que disponibilizam as imagens
de mamografia com a indicação de quais destas correspondem a exames de pacientes
doentes ou não.
10.3.1.2. Técnicas de Pré-Processamento
Em muitas aplicações, os métodos de processamento de imagens requerem ajustes na imagem de entrada para extrair suas informações de maneira satisfatória. Somente após estes
ajustes, a imagem é processada e se torna apta para análise na aplicação. Essa etapa de
pré-processamento pode ser definida por diversas técnicas como: remapeamento (para assegurar o sistema de coordenadas), redução de ruídos (para assegurar que as informações
são verdadeiras) e aumento de contraste (para assegurar que as informações relevantes
serão detectadas), entre outras.
Algumas distorções estão presentes em uma imagem e afetam a percepção da real
informação presente na mesma. Uma distorção crítica é a presença de ruído na imagem.
Esse fator implica em nova informação na imagem, diferente do seu comportamento real.
Normalmente, os ruídos são definidos por uma distribuição estatística, como o modelo
gaussiano, speckle e de poisson [Marques et al. 2004, Gonzalez e Woods 2007].
Para eliminação do ruído em uma imagem, faz-se necessário aplicar técnicas de
realce com processamento por máscara. Isso consiste em definir uma nova imagem, de
dimensão menor do que aquela a ser processada, e aplicar valores a cada um dos elementos dessa nova imagem que será chamada de máscara (ou janela). Essa janela percorre
toda a imagem, e faz uma avaliação pixel a pixel de acordo com sua dimensão. A distribuição de valores nessa máscara define o tipo de filtragem a ser executada: passa-alta
(preserva as informações de alta-frequência, como bordas e ruído, e elimina as demais)
ou passa-baixa (preserva as informações de baixa-frequência, como regiões homogêneas
221
Figura 10.2. Exemplos de filtragem. Ao lado esquerdo estão dispostas imagens
com resultados de tentativa de remoção de ruído com filtro passa-baixa. No lado
direito, um exemplo de detecção de borda com um filtro passa-alta.
em suas intensidades, e elimina o restante). Na Figura 10.2 estão dispostos exemplos de
filtros passa-baixa e passa-alta com suas respectivas máscaras. Cada máscara apresenta
um efeito diferenciado no resultado da filtragem [Paula 2009, Velho et al. 2009].
(a) Imagem original.
(b) Fatiamento da imagem em oito
pseudo-cores.
Figura 10.3. Exemplo de realce por uso de fatiamento de intensidades. Adaptado
de Gonzalez & Woods (2007).
Existem ainda outras técnicas que não realizam um processamento especial como
ocorre na filtragem, mas que permitem ajustar a imagem em seu pré-processamento. Uma
dessas técnicas é o fatiamento de intensidades, que permite criar uma nova codificação de
cores na imagem para melhor interpretá-la. Esse método é muito utilizado em aplicações
médicas e meteorológicas, em que as intensidades dos pixels são categorizadas em intervalos específicos. Cada interstício de intensidade assume uma cor na nova representação
da imagem. Um exemplo desse processo está na Figura 10.3 que apresenta uma imagem
monocromática do Fantasma de tireóide de Picker [Gonzalez e Woods 2007]. Com o fatiamento de intensidades, a imagem é redefinida com oito intervalos de intensidades onde
cada região assume uma pseudo-cor específica.
222
Há ainda técnicas de pré-processamento identificadas com a avaliação da estatística inerente à imagem para melhorar a sua aparência. Um exemplo muito prático consiste
na equalização do histograma da imagem. O histograma de uma imagem digital corresponde a uma estimativa da probabilidade de ocorrência dos seus níveis de cinza. Este
desenvolvimento produz uma imagem cujos níveis de cinza possuem uma densidade uniforme. Isso implica num aumento da escala dinâmica dos pixels, o que pode acarretar
em um efeito relevante na visualização da imagem [Gonzalez e Woods 2007]. A Figura
10.4 exibe amostras em condições diferentes de contraste e suas imagens de resultado
após a equalização dos seus respectivos histogramas. É possível perceber a mudança no
contraste destas imagens.
10.3.1.3. Segmentação
O processo de segmentação visa à separação dos pixels pertencentes a cada objeto presente na imagem. Isso implica em separação de regiões dentro da imagem analisada.
6000
5000
7000
7000
6000
6000
3500
5000
5000
3000
4000
4000
3000
3000
2000
2000
1000
1000
4000
4000
2500
3000
2000
1500
2000
1000
1000
0
0
0
50
100
150
200
250
500
0
0
50
100
150
200
250
0
0
50
100
150
200
250
0
50
100
150
200
250
0
50
100
150
200
250
7000
7000
5000
6000
6000
5000
5000
4000
4000
3000
3000
2000
2000
1000
1000
0
0
4000
3000
2000
0
50
100
150
200
250
1000
0
0
50
100
150
200
250
Figura 10.4. Realce na imagem através da equalização do histograma. Cada coluna apresenta quatro diferentes amostras de imagens: escura, clara, com baixo
contraste e com alto contraste. Analisando cada amostra a partir da imagem
de topo até a de base, tem-se: imagem original, histograma, efeito do realce e
histograma equalizado.
223
Exemplos desse processo incluem a seleção de regiões de interesse específicos e segmentação de uma ou mais regiões que contém um objeto de interesse [Castleman 1996].
A importância do realce em uma imagem é percebida no momento em que o processo de segmentação é efetuado. O método de segmentação precisa que a imagem tratada
esteja livre de distorções para atingir seu objetivo. A técnica mais simples é a limiarização
(ver Figura 10.5), que consiste em definir um valor de intensidade como limiar e modificar
todos os pixels da imagem com base no mesmo. Isso ocorre a partir de um comparativo,
no qual o pixel com intensidade menor ou igual ao limiar recebe valor 0 (zero). Em caso
contrário, a intensidade do pixel considerado receberá valor igual a 255. Portanto, duas
regiões são separadas na imagem.
3500
3000
2500
2000
1500
1000
500
0
0
(a)
50
100
150
200
250
(b)
(c)
(d)
Figura 10.5. Exemplo de segmentação por limiarização: (a) imagem original e (b)
seu respectivo histograma. Aplica-se o processo a partir do valor r = 125 aplicado
na (c) função de limiarização s = T (r) e obtém-se o (d) resultado da segmentação.
Adaptado de Gonzalez & Woods (2007).
10.3.1.4. Representação e Descrição de Formas
Com os agrupamentos obtidos a partir da segmentação da imagem, torna-se possível representar e descrever as regiões identificadas. Inicialmente, a representação de uma região pode ser caracterizada como baseada no contorno (fronteira), ou em termos de suas
características internas (pixels que compõem a região) [Paula et al. 2011]. Os dados da
região são enfim transformados em uma nova representação de acordo com a abordagem
escolhida e depois a mesma região é descrita. Esta descrição consiste em reconhecer características da região da imagem que possam diferenciá-la de outras regiões ou ainda de
outras imagens. Sendo assim, características matemáticas da imagem são extraídas em
vários níveis de complexidade. Exemplos básicos incluem detecção de bordas, cantos ou
pixels destacados na imagem [Costa e Cesar 2009].
Normalmente uma representação externa é escolhida quando as características da
forma são importantes. Por outro lado, se a atenção da aplicação está na cor e textura,
utiliza-se a representação interna. De toda maneira, as características selecionadas para o
descritor da forma devem ser afetadas o mínimo possível por variações de mudança de escala, rotação e translação da imagem. A representação da forma geralmente compacta os
dados em esquemas consideravelmente mais úteis no cálculo de descritores. A Figura 10.6
dispõe de duas assinaturas de formas. A primeira é uma representação funcional unidi-
224
Figura 10.6. Exemplo de realce por uso de fatiamento de intensidades. Adaptado
de Gonzalez & Woods (2007).
mensional de uma fronteira e pode ser gerada por maneiras distintas [Costa e Cesar 2009].
No exemplo apresentado, tem-se dois gráficos da distância da fronteira ao centróide em
função do ângulo para as formas de círculo e quadrado. Obtém-se assim, uma redução na
representação da forma a uma função unidimensional que se apresenta mais simples que
a imagem original.
Tabela 10.1. Exemplo de descrição de regiões. Na imagem à esquerda, imagem
do mapa da América separada em regiões. Proporção de luzes utilizado como
descritor, à direita. Adaptado de Gonzalez & Woods (2007).
Para gerar uma descrição de uma região é importante avaliar quais os descritores
que captam as diferenças essenciais entre os objetos ou classes de objetos. Diferentes
informações da imagem podem ser tratadas como descritores. Exemplos simples são área
e perímetro. A área de uma região é definida pelo número de pixels contidos dentro de
sua fronteira. O perímetro é o tamanho dessa fronteira. A Tabela 10.1 traz um exemplo de
descrição de uma representação de região. Utilizaram-se as informações de intensidade
dos pixels para identificar quantos detalhes de luzes podem ser reconhecidos nas regiões
da imagem apresentada (lado esquerdo da tabela). Um descritor foi definido a partir da
contagem de pontos que representam luz em cada região e foi possível diferenciá-los entre
si.
225
10.3.2. Reconhecimento de Padrões
Conforme [Jain et al. 2000], o estudo de reconhecimento de padrões teve início depois da
década de 60, quando foi desenvolvida a maior parte da teoria estatística moderna. Com
o advento dos computadores, cresceu ainda mais a demanda por aplicações de reconhecimento de padrões. Atualmente, o reconhecimento de padrões é utilizado em aplicações
envolvendo visão computacional, reconhecimento de caracteres, diagnóstico auxiliado
por computador, reconhecimento da fala, reconhecimento de impressão digital, autentificação de assinaturas, etc.
Existem muitos tipos de padrões, por exemplo: padrões visuais, padrões temporais, padrões lógicos. Pode-se dizer que tarefas de reconhecimentos de padrões são
encontradas em toda atividade inteligente. Deste modo, não há uma só teoria de reconhecimento de padrões que seja capaz de cobrir a grande quantidade de problemas possíveis.
Porém, existem algumas abordagens clássicas, incluindo: Reconhecimento Estatístico de
Padrões, Reconhecimento de Padrões usando Lógica Fuzzy, Reconhecimento de Padrões
usando Redes Neurais, Reconhecimento Sintático (ou Estrutural de Padrões) e Reconhecimento de Padrões Baseado em Conhecimento
A abordagem mais amplamente utilizada é a estatística. Dessa forma, os problemas de reconhecimentos de padrões são tratados como problemas de classificação. O que
consiste em associar um conjunto de atributos (características) de entrada a uma determinada categoria ou classe (saída). Em outras palavras, pode-se dizer que reconhecer
padrões equivale a classificar determinado objeto físico ou situação como pertencente ou
não a um certo número de categorias previamente estabelecidas. Há dois métodos de
classificação:
1. Supervisionada: em que uma amostra de dados é previamente conhecida, representada por um conjunto de padrões e suas respectivas classes. Neste método, a regra
de decisão pode ser representada por uma função densidade probabilidade, previamente conhecida (parametrizada) ou não (não parametrizada), ou por uma função
de classificação.
2. Não-Supervisionada: em que não há associação dos padrões e suas respectivas classes. O desafio será encontrar agrupamentos de dados e identificar suas respectivas
classes. Este método também é conhecido por clustering.
10.3.3. Atributos
Uma forma de classificar um objeto ou evento é medindo algumas de suas características ou algumas de suas propriedades mais representativas (features). Por exemplo, para
classificar uma letra impressa deve ser útil conhecer sua área e perímetro.
A especificação das características necessárias para uma boa classificação depende
das características do problema que se deseja resolver. Especificar esses atributos é uma
tarefa árdua que necessita de um elevado grau de experimentação com diferentes combinações de características.
Com frequência, um determinado objeto que se deseja classificar é representado
por um conjunto fixo de d atributos. Neste caso, é útil pensar no conjunto de atributos
226
como um vetor de atributos x, também chamado simplesmente de padrão, tal que x é um
vetor coluna de dimensão d.
10.3.4. Exemplos de Classificadores
O objetivo de um classificador é dividir o espaço de atributos em regiões de decisão.
Dessa forma, os vetores de atributos que estiverem contidos na mesma região de decisão
compartilham a mesma classe.
10.3.4.1. Vizinho mais Próximo
O algoritmo de classificação baseado no vizinho mais próximo (Nearest Neighbor - NN)
é uma técnica amplamente empregada para reconhecer padrões. O centro de seu funcionamento está em descobrir o vizinho mais próximo de uma dada instância. O NN é
considerado um dos mais simples algoritmos de aprendizagem de máquina. Ele funciona
bem quando a distância entre as médias é grande quando comparada com a dispersão de
cada classe em relação a sua média. Um resumo do funcionamento do classificador é
mostrado no Algoritmo 1.
Algoritmo 1 Algoritmo Vizinho Mais Próximo (Nearest Neighbor, NN).
1 Armazenar os exemplos em uma tabela.
2 Seja xnovo um vetor cuja classe é desconhecida, ou seja:
Classe(xnovo ) =?
3 Procurar na tabela o vetor armazenado mais próximo de xnovo .
4 Chamar de x prox o vetor armazenado mais próximo de xnovo .
5 Atribuir a xnovo a mesma classe de x prox , ou seja:
Classe(xnovo ) = Classe(x prox )
6 Se a classificação for correta incluir xnovo na tabela.
10.3.4.2. Distância Mínima aos Centróides (DMC)
O algoritmo Distância Mínima aos Centróides funciona de forma similar ao do Vizinho
Mais Próximo. No entanto, cada classe passa a ter um único vetor que a representa,
chamado de centróide. Dessa forma, não há necessidade de armazenar todos os exemplos
de uma classe o que nos leva a uma economia de memória. O centróide de uma classe é
o seu vetor médio; ou seja, a média dos exemplos daquela classe. Assim, pode-se dizer
que o centróide de uma classe é um modelo que representa aquela classe. Um resumo do
funcionamento do classificador é mostrado no Algoritmo 2.
227
Algoritmo 2 Algoritmo Distância Mínima aos Centróides (DMC).
1 Armazenar apenas os centróides das classes em uma tabela.
2 Seja xnovo um vetor cuja classe é desconhecida, ou seja:
Classe(xnovo ) =?
3 Procurar na tabela o centróide mais próximo de xnovo .
4 Chamar de C j o centróide mais próximo de xnovo .
5 Atribuir a xnovo a mesma classe de centróide mais próximo, ou seja:
Classe(xnovo ) = Classe(C j )
6 Se a classificação for correta, usar xnovo para recalcular C j .
10.3.4.3. Rede Neural Artificial
Uma rede neural artificial é composta por várias unidades de processamento, cujo funcionamento é paralelo e, por vezes, distribuído. Essas unidades, geralmente são conectadas
por canais de comunicação que estão associados a determinado peso, que é denominado
“peso sináptico”. As unidades fazem operações apenas sobre seus dados locais, que são
entradas recebidas pelas suas conexões. O comportamento inteligente de uma rede neural
artificial advém das interações entre as unidades de processamento da rede. O modelo de
um neurônio artificial pode ser visto na Figura 10.3.4.3.
Figura 10.7. Modelo de Neurônio Artificial baseado em Haykin (2001).
O comportamento das conexões entre os neurônios é simulado por meio de seus
pesos sinápticos. Os valores de tais pesos podem ser negativos ou positivos, dependendo
das conexões serem inibitórias ou excitatórias. O efeito de um sinal proveniente de um
outro neurônio é determinado pela multiplicação do valor (intensidade) do sinal recebido
pelo peso da conexão correspondente (xi ..pi ). É efetuada a soma dos valores xi ..pi de
todas as conexões, e o valor resultante é enviado para a função de ativação, que define a
saída (y) do neurônio. Combinando diversos neurônios, forma-se uma rede neural artifi-
228
cial. De uma forma simplificada, uma rede neural artificial pode ser vista como um grafo
onde os nós são os neurônios e as ligações fazem a função das sinapses.
A rede neural artificial é um sistema de neurônios ligados por conexões sinápticas
e dividido em neurônios de entrada, que recebem estímulos do meio externo, neurônios
internos ou hidden (ocultos) e neurônios de saída, que se comunicam com o exterior. A
forma de arranjar perceptrons em camadas é denominado Multilayer Perceptron (MLP).
O MLP foi concebido para resolver problemas mais complexos, os quais não poderiam
ser resolvidos pelo modelo de neurônio básico. Para isto são necessárias mais conexões,
os quais só existem em uma rede de perceptrons dispostos em camadas. Na Camada
escondida, camada oculta ou camada intermediária, como também é conhecida os neurônios são denominados escondidos porque eles não tem acesso direto a saída da rede MLP,
onde os erros de aproximação são calculados.
10.4. Aplicações
Nesta seção apresentamos duas aplicações do processamento digital de imagens no diagnóstico auxiliado por computador. A primeira é a identificação de estruturas da retina. A
identificação dessas estruturas auxiliam no diagnósticos de várias doenças como a retinopatia diabética e o edema macular. A segunda envolve o reconhecimento e a análise de
posturas humanas. Estas aplicações utilizam imagens obtidas em ambientes clínicos para
o tratamento de desvios posturais.
10.4.1. Identificação de Estruturas da Retina
A retina constitui a membrana mais interna do olho, situando-se na parede posterior.
Quando o olho focaliza uma cena, a imagem correspondente é projetada sobre a retina, na
qual estão distribuídos dois tipos de receptores de luz: os cones e os bastonetes. Os cones
são são responsáveis pela chamada visão fotóptica ou de luz clara. Já os bastonetes são
úteis para detectar detalhes.
Entre os padrões presentes no fundo do olho, encontra-se a rede de veias da retina,
que pode revelar uma série de doenças ligadas às variações ocorridas no globo ocular. O
tratamento para essas doenças se torna mais eficaz quanto mais cedo elas são descobertas,
e isso se dá através de exames oftalmológicos periódicos [Hajer et al. 2006].
Imagens digitais de retina podem prover informações sobre mudanças patológicas
causadas por doenças oculares locais e sinais recentes de doenças sistemáticas como a
hipertensão, a arterioesclerose e o Diabetes Mellitus (DM). A análise e interpretação desse
tipo de imagem vem se tornando um auxílio importante e necessário no diagnóstico dessas
doenças.
10.4.1.1. Disco Óptico
Nos sitemas CAD para detecção de doenças oculares usando imagens coloridas de retina,
a localização automática do disco óptico (DO) e o cálculo do seu contorno são passos
fundamentais, antes de qualquer análise. A segmentação do disco óptico é um passo
importante no pré-processamento de vários algoritmos desenvolvidos para a extração au-
229
tomática das estruturas anatômicas e para a detecção de lesões na retina. Além disso,
esse processo também atua como um indicador de patologias oftalmológicas, como o
glaucoma, que é uma das causas mais comuns de cegueira [Xu et al. 2007].
A identificação do disco óptico é também essencial na localização dos vasos, os
quais, fornecem uma referência que pode facilitar o processo da detecção da posição de
outras estruturas do fundo ocular e de lesões. Além disso, é essencial a remoção prévia
do disco óptico nos algoritmos de detecção de exudatos1 , dada a semelhança entre ambos
em termos de cor, brilho e contraste [Gagnon et al. 2001].
Basicamente, podemos classificar os algoritmos de detecção do disco óptico em
duas classes: abordagem geográfica e abordagem baseada em características locais. Os
algoritmos que usam a abordagem geográfica baseiam-se na informação fornecida pela
estrutura dos vasos, isto é, no fato de todos os vasos da retina terem origem no disco óptico. Embora a detecção dos vasos seja uma operação complexa, a sua relação geométrica
com o disco óptico pode ser utilizada para identificar a localização deste. Uma vez conhecida a localização do disco óptico, este é detectado como ponto inicial para determinar o
respectivo contorno.
Os algoritmos baseados nas características locais levam em consideração, principalmente, a sua forma redonda e brilho relativamente elevado, quando comparado com o
resto da imagem. Em [Veras et al. 2011] os principais algoritmos de detecção do disco
óptico foram avaliados e o método proposto por [Hoover e Goldbaum 2003].
A Figura 10.8 apresenta três exemplos de imagens de retina. Na Figura 10.8(a) o
contorno do disco óptico é bem definido o que torna mais fácil sua detecção. Já na Figura
10.8(b), o plano de fundo é bastante heterogêneo e a região central possui intensidade de
cor bem próxima a da região do disco óptico. A Figura 10.8(c) apresenta uma imagem
onde não é possível a identificação do disco óptico.
(a)
(b)
(c)
Figura 10.8. Exemplos de imagens da base STARE
10.4.1.2. Mácula
A detecção da mácula é uma tarefa relevante no processamento de imagens de fundo
de olho (retina) e é utilizada em várias aplicações. Ela é considerada um importante
1 Produto
seroso, purulento, resultante de processo inflamatório.
230
marcador fisiológico na análise de imagens da retina e é usada na localização de outras
estruturas da retina como o DO, microvasos e exsudatos [Winder et al. 2009].
A mácula é um ponto ovalado de cor amarela junto ao centro da retina do olho
humano e tem um diâmetro de cerca 1,5 mm. A região da mácula possui uma sub-região
chamada fóvea, que localiza-se no centro da mácula e possui uma área menor que a mácula. É nesta última que encontramos uma maior quantidade de cones (células responsáveis pela percepção de cores). A mácula contém uma pigmentação mais escura e sua
localização é aproximadamente o centro da retina. De acordo com [Tobin et al. 2007], o
raio da mácula é igual ao dobro do raio do DO e a fóvea mede metade do raio do DO.
Uma detecção precisa da mácula é um importante primeiro parâmetro para determinar patologias como a Degeneração e o Edema Macular. O diagnóstico de Edema
Macular, por exemplo, é realizado levando-se em consideração a quantidade de exsudatos
e suas localizações com relação à região da mácula.
O algoritmo de detecção da mácula, na maioria dos trabalhos publicados, determina uma Região de Interesse (ROI - Region of Interest) baseado na localização do DO,
como mostra a Figura 10.9. Após a determinação da ROI, algoritmos específicos são executados para definir o centro da mácula. Uma descrição e avaliação de vários métodos de
detecção da mácula pode ser encontrada em [Silva et al. 2011].
Figura 10.9. Ilustração da ROI.
10.4.1.3. Microaneurismas e Exsudatos
A Retinopatia Diabética (RD) é uma doença assintomática nas fases iniciais, o que dificulta a sua detecção. Ela ocorre como resultado das alterações vasculares na retina
causando inchaços de capilares, conhecidos como microaneurismas (MA). Estes podem
romper-se, e, eventualmente, se tornarem uma fonte de extravasamento de plasma causando o espessamento da retina, ou edema, se ocorrem na região macular, e pode causar
perda de visão de alta qualidade [Fleming et al. 2007]. O espessamento da retina não é
facilmente visível nas fotografias do fundo do olho, portanto, regiões de depósitos de gordura, conhecidas como exsudatos, são usadas como marcadores. Exsudatos geralmente
formam aglomerados, e podem ser distribuídos em toda a retina ou podem aparecer em
um anel em torno de um ponto central do vazamento.
231
A Organização Mundial de Saúde estima que 135 milhões de pessoas tenham
diabetes no mundo e que este número de diabéticos deverá aumentar para 300 milhões até
o ano de 2025 [Amos et al. 1997]. A RD afeta uma parte considerável da população, o que
justifica trabalhos avançados na área de detecção de doenças por imagens. Desenvolvendo
técnicas simples, e com um custo-benefício baixo, seria possível a detecção da RD em sua
fase inicial. Estudos comprovam que quanto mais cedo for detectada a RD mais chances
o paciente terá de não desenvolver a doença em seu grau mais elevado.
Microaneurismas se apresentam como os primeiros padrões patológicos que surgem na retina humana, em portadores de Retinopatia Diabética, e constituem uma evidência direta de isquemia, uma vez que cada microaneurisma representa a oclusão de ao
menos um vaso capilar. Portanto, existe uma relação entre o número de microaneurismas
e o agravamento da doença em pacientes portadores do Diabetes Mellitus, ou simplesmente Diabetes, como é popularmente conhecida. Sistemas automáticos de detecção de
microaneurismas vêm sendo bastante utilizados em substituição aos sistemas manuais de
contagem, uma vez que estes consomem muito tempo e são mais sujeitos a erros. Alguns
dos principais métodos são [Fleming et al. 2007, Walter et al. 2002, Martins et al. 2008].
Com o avanço da Retinopatia Diabética aparecem os exsudatos. Quando isso
ocorre a doença já se encontra em um nivel grave, mas ainda pode ser controlada. A
Figura 10.10(a) é um exemplo de retina saudável. Já na Figura 10.10(b) existe alguns
exsudatos bem pequenos na região central da retina. A Figura 10.10(c) apresenta vários
exsudatos e hemorragias.
(a)
(b)
(c)
Figura 10.10. Exemplos de imagens com e sem exsudatos
Basicamente existem três técnicas diferentes de detecção exsudatos em imagens
da retina. A primeira funciona através da definição de um limiar como foi observado em
[Kavitha e Shenbaga 2005]. Essa técnica não possui um bom desempenho, pois como o
disco óptico possui propriedades de cor semelhante a dos exsudatos muitas vezes ele é
marcado incorretamente como exsudato. Outro problema dessa técnica ocorre quando
aparecem regiões mais claras na imagem, elas também podem ser marcadas como exsudatos.
A segunda técnica utiliza agrupamento de pixels, como em [Sopharak et al. 2010].
Essa é a principal técnica usada para a detecção dos exsudatos, porém isoladamente ela
não produz resultados satisfatórios, pois muitas vezes é necessário o uso de classificação
ou morfologia matemática para eliminar falsos candidatos [de Araújo et al. 2011].
A terceira técnica faz uso de operações de morfologia matemática, como foi ob-
232
servado em [Walter et al. 2002]. Assim como no agrupamento, essa técnica não produz
bons resultados isoladamente. Geralmente ela é usada para remover falsos candidatos ou
pixels isolados.
10.4.1.4. Microvasos
Imagens de fundo de olho fornecem informações sobre as mudanças patológicas causadas por doenças oculares. Uma característica importante para o diagnóstico de doenças
como diabetes, arteriosclerose e hipertensão é a aparência dos vasos sanguíneos na retina
[Li et al. 2006]. O desenvolvimento de uma solução computacional para a segmentação
dos vasos sanguíneos permite que o médico especialista diagnostique melhor os casos
de vascularidade anormal. Em outros casos, o desempenho de métodos automáticos de
detecção (segmentação) de vasos auxilia no diagnóstico de outras doenças como foi apresentado em [Martins et al. 2009].
Entretanto, essa segmentação é dificultada pelos seguintes fatos [Li et al. 2006]:
a largura dos vasos pode variar de muito larga a muito fina e o contraste local dos vasos
não é estável. Várias abordagens para segmentação de vasos são encontradas na literatura
[Zana e Klein 2001, Niemeijer et al. 2004, Soares et al. 2006].
A Figura 10.4.1.4 apresenta um exemplo de imagem de retina e o resultado de
dois métodos diferentes de segmentação de vasos.
(a)
(b)
(c)
Figura 10.11. Imagem de retina com duas segmentações de vasos
10.4.2. Postura
Postura é geralmente definida como o arranjo relativo das partes do corpo. Dessa maneira, a postura correta traduz o estado de equilíbrio muscular e esquelético que protege
as estruturas de suporte do corpo contra lesão ou deformidade progressiva. Independente
da atitude assumida pelo paciente (agachada, ereta, deitada), estas estruturas estão trabalhando ou repousando. Os órgãos torácicos e abdominais mantêm-se em posições ideais
e os músculos funcionam com mais eficiência sob tais condições. [Furlaneto et al. 2007]
Consequentemente, com a má postura ocorre uma relação defeituosa entre várias partes
do corpo. Isso produz uma maior tensão sobre estruturas de suporte e onde ocorre um
equilíbrio menos eficiente do corpo [Ferreira et al. 2011].
233
Entre diversos tratamentos fisioterapêuticos existentes, a Reeducação Postural Global (RPG) é um método que atua na dor e no desconforto provocados por alterações posturais. Diferente das outras abordagens, o tratamento por RPG leva em consideração que
o corpo humano é um sistema muscular integrado. Portanto, há a necessidade da observação de toda a silhueta humana independentemente da localização do desvio de postura
[Ferreira et al. 2010].
A Figura 10.12 traz a caracterização da coluna vertebral, que é dividida em quatro
curvaturas. Duas delas com a concavidade virada para trás (lordoses nas regiões cervical e lombar) e duas delas com a concavidade virada para a frente (cifoses nas regiões
toráxica e pélvica, ver Figura 10.12(a)). Em geral, as imagens para o diagnóstico são tomadas em vários planos de observação. Alguns desvios da postura podem ser observados
em imagens do plano frontal do paciente, como a escoliose (Figura 10.12(b)). Imagens
adquiridas em plano sagital provêem conhecimento de desvios posturais, tais como hipercifose dorsal, hiperlordose lombar e hiperlordose cervical. Também é possível mensurar
a angulação da tíbia em relação ao pé, flexão e extensão dos joelhos e inclinação anterior
e posterior da pélvis [Passarinho et al. 2006, Ferreira et al. 2011].
(a)
(b)
Figura 10.12. Caracterização da (a) coluna vertebral e suas regiões ou curvaturas (Fonte: Wikipédia). Como exemplo de desvio, a (b) escoliose que pode ser
percebida no plano frontal (Fonte: Wikipédia).
Passarinho e outros autores apresentaram em [Passarinho et al. 2006] uma metodologia utilizada para avaliação de mudanças no equilíbrio postural em pacientes submetidos à RPG. Este trabalho descreve uma medida de similaridade com o intuito de obter
melhor desempenho na quantificação das alterações posturais.
O procedimento se inicia com o cálculo das assinaturas das formas dos pacientes.
Estas formas são obtidas de segmentações aplicadas sobre as imagens obtidas pelo fisioterapeuta. Esta assinatura traz uma nova representação da forma com uma relação entre
a curvatura e a informação de ângulo, em relação ao centróide, de cada um dos pontos
234
do contorno da forma. A função de curvatura descreve a variância da direção assumida
pelo contorno da forma [Cesar e Costa 1996]. Quanto mais ereta é a postura do paciente,
sua função de curvatura correspondente alcançará menor amplitude. A Figura 10.13(a)
mostra a comparação entre duas assinaturas polares de um mesmo paciente antes e depois
do tratamento. O método descrito em [Passarinho et al. 2006] usa como medida de similaridade o cálculo da diferença de áreas sob as assinaturas e é inversamente proporcional
à diferença da área sob
as curvas das assinaturas. Esta medida, SM, é calculada através da
relação: SM = 1 − 1 S, em que S é a diferença das áreas sob as assinaturas polares dos
perfis sagitais em estudo.
Este mesmo método avaliou sua medida de similaridade em comparação com a
proposta em [Bernier e Landry 2003] para um conjunto de imagens adquiridas em 22 pacientes. Cada um deles possibilita a aquisição de duas imagens para que sejam obtidas
suas respectivas formas. O objetivo é demonstrar que a medida SM mostra-se mais sensível às mudanças da postura do paciente após o tratamento de RPG. Os resultados podem
ser vistos na Figura 10.13(b). Os valores alcançados para essa medida significam que o
paciente em questão obteve resposta mais significativa ao tratamento fisioterapêutico.
(a)
(b)
Figura 10.13. Análise de similaridade de formas: (a) há a correspondência das
assinaturas polares de um paciente antes (azul) e após (vermelho) o RPG; (b)
similaridade para os contornos sagitais de 22 pacientes distintos. Adaptado de
[Passarinho et al. 2006].
Uma aplicação em fisioterapia utilizando o Software de Análise Postural (SAPO)
como um sistema CAD foi proposto em [Ferreira et al. 2011]. Este possui características
distintas quando comparado com outros softwares disponíveis, porque inclui a análise
de postura global do corpo e a análise de ângulos e distâncias de maneira independente.
Permite o arquivamento e comparação de fotografias para observar a evolução do paciente
em determinado tratamento. O software também permite calibração e ajustes de foto para
evitar erros de medição pequenos e aumentar a confiabilidade do método.
Ferreira e outros autores, com o auxílio deste software citado, realizaram uma
avaliação quantitativa global do alinhamento postural de adultos jovens e saudáveis em
pé, com base em pontos de vista anterior, posterior e lateral. O trabalho envolveu 122
participantes que foram submetidos a uma análise de agrupamento pela similaridade das
variáveis do estudo. O sistema indica a marcação de 50 pontos anatômicos distribuídos
entre as visões anterior, laterais e posterior, como o lóbulo da orelha, a linha de junção
235
do joelho, calcâneo, ângulo inferior da escápula, entre outros. Destes total, 16 deles
eram bilaterais [Ferreira et al. 2010]. Alguns destes pontos estão visíveis na Figura 10.14.
Este estudo e o software estão disponíveis em http://sapo.incubadora.fapesp.br, e inclui
tutoriais científicos, bem como vários recursos de apoio à análise de fotografias.
Figura 10.14. Pontos anatômicos e ângulos avaliados nas visões laterais. Adaptado de [Ferreira et al. 2011].
Os dados foram submetidos à análise estatística descritiva. Valores quantitativos
para a cabeça, membros superiores e inferiores, e alinhamento do tronco foram obtidos,
juntamente com a freqüência das inclinações para a esquerda e direita. As medidas utilizadas para análise da postura incluiram distâncias (em centímetros) e ângulos (em graus),
extraídos da combinação de pontos anatômicos descritos em [Ferreira et al. 2011]. As variáveis da avaliação postural foram analisadas através da média, desvio padrão e valores
de máximo e mínimo.
Vários valores de referência padrão de referência foram definidos neste estudo
para avaliar o alinhamento postural. Membros inferiores mostraram alinhamento similar.
A posição da cabeça, tronco e membros superiores e inferiores em vistas laterais são
apresentados na Tabela 10.2. Medidas envolvendo o quadril, tornozelo, cifose, lordose e
mostrou maior variabilidade. Existem pequenas variações no alinhamento dos segmentos
corporais nas visões anterior e posterior em indivíduos saudáveis.
Os resultados do estudo demonstraram uma tendência de assimetria entre os segmentos bilaterais na visão anterior, com a pélvis, ombros e tronco mostrando ligeira inclinação para a direita. Na visão posterior, uma pequena assimetria foi observada no posicionamento da pélvis e escápula. Maiores detalhes, como identificação dos outros pontos
anatômicos e o resultado detalhado da análise das variáveis da postura estão descritos em
[Ferreira et al. 2011].
236
Tabela 10.2. Valores de média (desvio padrão), mínimo e máximo para as variáveis de postura observadas nas visões laterais, medidas em ângulos. Adaptado
de [Ferreira et al. 2011].
Variáveis (◦ )
Média (desvio padrão)
Alinhamento horizontal da cabeça
47,1 (4,8)
Alinhamento horizontal da pélvis
172,6 (4,8)
Alinhamento sagital do membro inferior
177,9 (4,8)
Ângulo de junção do quadril
149,8 (8,0)
Ângulo de junção do maléolo
86,2 (2,6)
Alinhamento vertical do torso
182,4 (2,1)
Alinhamento vertical do corpo
178,2 (0,9)
Alinhamento do membro superior
155,8 (5,1)
Alinhamento sagital do corpo
186,8 (3,6)
Ângulo da cifose torácica
55,4 (7,4)
Ângulo da lordose lombar
47,7 (15,4)
Mínimo
31,2
158,6
166,7
129,7
79,9
177,6
175,8
145,7
176,4
39,3
23,3
Máximo
58,4
182,4
190,6
176,2
91,6
187,0
180,0
170,7
198,5
68,2
96,4
10.5. Conclusão
Estre trabalho apresentou, com base em publicações científicas, que a utilização de algoritmos computacionais para auxílio à análise de imagens médicas tem-se mostrado eficiente na melhoria da detecção e classificação de lesões e/ou patologias humanas. Existem
aplicações em diferentes especialidades e todas com resultados eficientes para distintas
análises clínicas.
É importante ressaltar que o objetivo de um sistema CAD está na realização de
uma análise automatizada como forma de auxílio, e não um substituto para o especialista
da área da saúde. Portanto, é exigido que toda aplicação dessa natureza apresente um
desempenho próximo ao desse especialista. O acompanhamento deste último ao processo
de desenvolvimento do sistema CAD é um fator que incrementa confiança e eficiência aos
resultados da aplicação.
Referências
[Amos et al. 1997] Amos, A. F., MacCarty, D. J., e Zimmet, P. (1997). The rising global
burden of diabetes and its complications: Estimates and projections to the year 2010.
Diabetc Medicine, 14:S1–S85.
[Azevedo et al. 2007] Azevedo, E., Conci, A., e Leta, F. R. (2007). Computação Gráfica:
Processamento de Imagens Digitais, volume 2. Editora Campus.
[Bernier e Landry 2003] Bernier, T. e Landry, J.-A. (2003). A new method for representing and matching shapes of natural objects. Pattern Recognition, 36(8):1711–1723.
[Burger e Burge 2009] Burger, W. e Burge, M. J. (2009). Principles of Digital Image
Processing: Fundamental Techniques. Springer.
[Castleman 1996] Castleman, K. R. (1996). Digital Image Processing. Prentice Hall,
Upper Saddle River.
237
[Cesar e Costa 1996] Cesar, R. M. J. e Costa, L. F. (1996). Towards effective planar shape
representation with multiscale digital curvature analysis based on signal processing
techniques. Pattern Recognition, 28(9):1559–1569.
[Costa e Cesar 2009] Costa, L. F. e Cesar, R. M. J. (2009). Shape Analysis and Classification: Theory and Practice. CRC Press, 2a edição.
[de Araújo et al. 2011] de Araújo, F., Veras, R., e Silva, R. (2011). Aperfeiçoamento da
detecção de exsudatos com k-means fuzzy, detecção de vasos e morfologia matemática.
In V Escola Regional de Computação dos Estados do Ceará, Maranhão e Piauí.
[Doi 2007] Doi, K. (2007). Computer-aided diagnosis in medical imaging: Historical review, current status and future potential. Computerized Medical Imaging and
Graphics, 31:198–211.
[Ferreira et al. 2011] Ferreira, E. A., Duarte, M., Maldonado, E. P., Bersanetti, A. A., e
Marques, A. P. (2011). Quantitative assessment of postural alignment in young adults
based on photographs of anterior, posterior, and lateral views. Journal of Manipulative
and Physiological Therapeutics, 34(6):371–380.
[Ferreira et al. 2010] Ferreira, E. A. G., Duarte, M., Maldonado, E. P., Burke, T. N., e
Marques, A. P. (2010). Postural assessment software (PAS/SAPO): Validation and
reliabiliy. Clinics, 65:675–681.
[F.F. et al. 1991] F.F., Y., M.L., G., K., D., C.E., M., C.J., V., e R.A., S. (1991). Computerized detection of masses in digital mammograms: analysis of bilateralsubtraction
images. Med Phys, páginas 55–63.
[Fleming et al. 2007] Fleming, A. D., Goatman, K. A., Philip, S., Olson, J. A., e Sharp,
P. F. (2007). Automatic detection of retinal anatomy to assist diabetic retinopathy
screening. Physics in Medicine and Biology, 52(2):331–345.
[Furlaneto et al. 2007] Furlaneto, T. S., Candotti, C. T., e Loss, J. F. (2007). Desenvolvimento de uma metodologia digital para avaliação postural no plano sagital. In Anais
do XII Congresso Brasileiro de Biomecânica, São Pedro - SP.
[Gagnon et al. 2001] Gagnon, L., Lalonde, M., Beaulieu, M., e Boucher, M. C. (2001).
Procedure to detect anatomical structures in optical fundus images. In Proceedings of
Conference Medical Imaging, volume 4322, páginas 1218–1225, San Diego.
[Gomes e Velho 1994] Gomes, J. e Velho, L. (1994). Computação Gráfica: Imagem.
IMPA.
[Gonzalez e Woods 2007] Gonzalez, R. C. e Woods, R. E. (2007). Digital Image Processing. Prentice Hall, Nova York, EUA, 3a edição.
[Hajer et al. 2006] Hajer, J., Kamel, H., e Noureddine, E. (2006). Blood vessels segmentation in retina image using mathematical morphology and the STFT analysis.
Information and Communications Technologies, 1:1130–1134.
238
[Hong Shao 2004] Hong Shao, Wen-Cheng Cui, H. Z. (2004). Automatic analysis of
brain pathology based on image content. In IEEE International Conference on Systems.
[Hoover e Goldbaum 2003] Hoover, A. e Goldbaum, M. (2003). Locating the optic nerve
in a retinal image using the fuzzy convergence of the blood vessels. IEEE Transactions
on Medical Imaging, 22(8):951–958.
[Jain et al. 2000] Jain, A. K., Duin, R. P., e Mao, J. (2000). Statistical pattern recognition:
A review. IEEE Transactions on Pattern Analysis and Machine Intelligence, 22(1):4–
37.
[Kavitha e Shenbaga 2005] Kavitha, D. e Shenbaga, S. (2005). A cellular neurofuzzy
network for contrast enhancement of fundus images with retinopathies. In Proceeding
ICS’06 Proceedings of the 10th WSEAS international conference on Systems.
[Li et al. 2006] Li, Q., Zhang, L., Zhang, D., e Bhattacharya, P. (2006). A new approach
to automated retinal vessel segmentation using multiscale analysis. In ICPR, páginas
77–88. IEEE Computer Society.
[Marques 2001] Marques, P. (2001). Diagnóstico auxiliado por computador na radiologia. Radiol Bras, 34(5):285–293.
[Marques et al. 2004] Marques, R., Carvalho, E., Costa, R., e Medeiros, F. (2004).
Filtering effects on sar images segmentation. Lecture Notes in Computer Science,
3124:1041–1046.
[Martins et al. 2008] Martins, C., R.M.S.Veras, G.L.B.Ramalho, F.N.S.Medeiros, e
Ushizima, D. M. (2008). Automatic microaneurysm detection and characterization
through digital color fundus images. In II Workshop on Computational Intelligence SBRN, páginas 45–50.
[Martins et al. 2009] Martins, C. I. O., Medeiros, F. N. S., e ans F. N. Bezerra ans R. M.
Cesar Jr., R. M. S. V. (2009). Evaluation of retinal vessel segmentation methods for
microaneurisms detection. In International Conference on Image Processing (ICIP),
páginas 3365–3368.
[Niemeijer et al. 2004] Niemeijer, M., Staal, J. J., van Ginneken, B., Loog, M., e Abràmoff, M. D. (2004). Comparative study of retinal vessel segmentation methods on
a new publicly available database. In Fitzpatrick, J. M. e Sonka, M., editors, SPIE
Medical Imaging, volume 5370, páginas 648–656.
[Passarinho et al. 2006] Passarinho, C. J. P., Cintra, L. H. S., Medeiros, F. N. S., Oliveira, I. N. S., e Paula, I. C. J. (2006). Análise de similaridade e correspondência de
formas aplicada à reeducação postural global. In Anais do XX Congresso Brasileiro de
Engenharia Biomédica, páginas 117–120, São Pedro - SP.
[Paula 2009] Paula, I. C. J. (2009). Livro Texto dos Minicursos - Ercemapi 2009, capítulo
Técnicas de Processamento Digital de Imagens com Java. SBC, Parnaíba - PI.
239
[Paula et al. 2011] Paula, I. C. J., Medeiros, F. N. S., Bezerra, F. N., e Ushizima, D. M.
(2011). Corner detection within a multiscale framework. In Proceedings of Sibgrapi
2011 (XXIV Conference on Graphics, Patterns and Images), Maceió - AL. IEEE.
[Silva et al. 2011] Silva, R., Veras, R., e de Araújo, F. (2011). Avaliação de métodos para
detecção da mácula em imagens da retina. In V Escola Regional de Computação dos
Estados do Ceará, Maranhão e Piauí.
[Soares et al. 2006] Soares, J. V. B., Leandro, J. J. G., Cesar-Jr., R. M., Jelinek, H. F.,
e Cree, M. J. (2006). Retinal vessel segmentation using the 2-D Gabor wavelet and
supervised classification. IEEE Transactions on Medical Imaging, 25:1214–1222.
[Sopharak et al. 2010] Sopharak, A., Dailey, N., Uyyanonvara, B., Barman, S., Williamson, T., New, T. N., e Moe, A. Y. (2010). Machine learning approach to automatic
exudate detection in retinal images from diabetic patients. Journal of Modern Optics,
(57):124–135.
[Thurfjell et al. 1994] Thurfjell, E. L., Lernevall, K. A., e Taube, A. A. (1994). Benefit of
independent double reading in a population-based mammography screening program.
Radiology, 191:241–244.
[Tobin et al. 2007] Tobin, K. W., Chaum, E., Govindasamy, V. P., e Karnowski, T. P.
(2007). Detection of anatomic structures in human retinal imagery. IEEE Transactions
on Medical Imaging, 26(16):1729–39.
[Velho et al. 2009] Velho, L., Frery, A., e Gomes, J. (2009). Image Processing for Computer Graphics and Vision. Springer, 2a edição.
[Veras et al. 2011] Veras, R., Araújo, F., Silva, R., Medeiros, F., e Aires, K. (2011). omparação e avaliação de métodos de detecção do disco Óptico. In XXXVII Conferencia
Latinoamericana de Informática.
[Walter et al. 2002] Walter, T., Klevin, J., Massin, P., e Erginay, A. (2002). A contribution
of image processing to the diagnosis of diabetic retinopathy-detection of exudates in
color fundus images of the human retina. IEEE Transactions on Medical Imaging,
21(10):1236 – 1243.
[Winder et al. 2009] Winder, R., Morrow, P., McRitchie, I., Bailie, J., e Hart, P. (2009).
Algorithms for digital image processing in diabetic retinopathy. Computerized Medical
Imaging and Graphics, page 15.
[Xu et al. 2007] Xu, J., Chutatape, O., e Chew, P. (2007). Automated optic disk boundary detection by modified active contour model. IEEE Transactions on Biomedical
Engineering, 54(3):473–482.
[Zana e Klein 2001] Zana, F. e Klein, J. C. (2001). Segmentation of vessel-like patterns using mathematical morphology and curvature evaluation. IEEE Transactions on
Image Processing, 10:1010–1019.
240

Documentos relacionados