• Nenhum resultado encontrado

Plugins: uma alternativa para o desacoplamento, modularização e extensão de funcionalidades no desenvolvimento de software

N/A
N/A
Protected

Academic year: 2021

Share "Plugins: uma alternativa para o desacoplamento, modularização e extensão de funcionalidades no desenvolvimento de software"

Copied!
157
0
0

Texto

(1)

UNIVERSIDADE FEDERAL DE SANTA CATARINA

SISTEMAS DE INFORMAÇÃO

FABIANO VICENTE SIEGEL

PLUGINS

UMA ALTERNATIVA PARA O DESACOPLAMENTO, MODULARIZAÇÃO E

EXTENSÃO DE FUNCIONALIDADES NO DESENVOLVIMENTO DE SOFTWARE

FLORIANÓPOLIS

2009

(2)

FABIANO VICENTE SIEGEL

PLUGINS

UMA ALTERNATIVA PARA O DESACOPLAMENTO, MODULARIZAÇÃO E

EXTENSÃO DE FUNCIONALIDADES NO DESENVOLVIMENTO DE SOFTWARE

Trabalho de conclusão de curso apresentado

como parte dos requisitos para obtenção de

grau

em

Bacharel

em

Sistemas

de

Informação, da Universidade Federal de

Santa Catarina.

Orientador:

FRANK AUGUSTO SIQUEIRA

FLORIANÓPOLIS

2009

(3)

FABIANO VICENTE SIEGEL

PLUGINS

UMA ALTERNATIVA PARA O DESACOPLAMENTO, MODULARIZAÇÃO E

EXTENSÃO DE FUNCIONALIDADES NO DESENVOLVIMENTO DE SOFTWARE

Trabalho de conclusão de curso apresentado

como parte dos requisitos para obtenção de

grau

em

Bacharel

em

Sistemas

de

Informação, da Universidade Federal de

Santa Catarina.

Banca Examinadora

Orientador: Profº Frank Augusto Siqueira

Profº Raul Sidnei Wazlawick

(4)

DEDICATÓRIA

Dedico este trabalho a Deus, que nos momentos de dificuldade me mostra a

oportunidade de melhorar, e aos meus pais, que através de seus exemplos de vida

me ensinam que o Ser é mais importante que o Ter.

(5)

AGRADECIMENTO

Agradeço ao meu orientador, Prof. Dr. Frank Siqueira, pela confiança depositada e

pela oportunidade de realizar este trabalho.

Agradeço aos colegas da Audaces por despertar interesse em temas relevantes ao

desenvolvimento de software.

Agradeço à minha namorada, Tatiana Farias, pelo apoio incondicional durante a

realização deste trabalho.

Agradeço aos meus amigos pela compreensão, pois em diversas vezes receberam

um “não” como resposta, devido a minha indisponibilidade.

(6)

Não existe, neste mundo todo, uma superioridade real que

possa ser separada de uma vida correta.

(7)

RESUMO

Com o passar do tempo, a arquitetura dos sistemas evoluiu para um design mais

modular. Um dos fatores que influenciou essa evolução foi a necessidade de

aumentar o reuso de código. Essa melhoria permite que sistemas não sejam escritos

do zero a cada nova implementação. Uma forma de conseguir essa modularização e

conseqüentemente aumentar o reuso de código é através do uso de plugins no

desenvolvimento dos sistemas. Este trabalho aborda a utilização de plugins como

uma alternativa para melhorar a qualidade da arquitetura de software. Com esse

objetivo, apresentamos o conceito de plugins como um padrão de projeto e

estudamos algumas aplicações comerciais, a fim de complementar a bibliografia

acadêmica. No decorrer deste trabalho, modelamos uma pequena biblioteca escrita

em C++, para facilitar a utilização de plugins. Por fim, um sistema existente é

adaptado para usar o conceito estudado.

(8)

ABSTRACT

Over time, systems architecture has evolved into a more modular design. One of the

factors that influenced this evolution was the need to increase the reuse of code. This

improvement avoids the problem of re-writing the system from scratch with each new

implementation. One way to achieve this modularization and therefore increase the

reuse of code is through the use of plugins. This paper discusses the use of plugins

as an alternative to improve the quality of software architecture. As a way to achieve

that, we present the concept of plugins as a design pattern. We also present the

study of some commercial applications to complement the academic literature.

During the course of the work, we model a small library, written in C++, in order to

make the use of plugins easier. Finally, an existing system is adapted to use the

concepts studied.

(9)

LISTA DE ABREVIAÇÕES E SIGLAS

API – Application Programming Interface (ou Interface de Programação de

Aplicativos)

AV – Acrobat Viewer

AS – Acrobat Support

BHO – Browser Helper Object (Objeto de Ajuda de Navegação)

COM – Component Object Model (Modelo de Objeto Componente)

Cos – Cos Object System

DLL – Dynamic-link library (Biblioteca de ligação dinâmica)

GUI – Graphical User Interface (Interface Gráfica do Usuário)

IDE

Integrated

Development

Environment

(Ambiente

Integrado

de

Desenvolvimento)

PD – Portable Document (Documento Portável)

PDF – Portable Document Format (Formato de Documento Portável)

SDK – Software Development Kit (Kit de Desenvolvimento de Software)

XML – eXtensible Markup Language (Linguagem de Marcação Extensível)

(10)

LISTA DE FIGURAS

Figura 1. Diferença entre a primeira e segunda geração de plugins. ... 15

Figura 2. Diagram UML do padrão Plugin. ... 15

Figura 3. Camadas de uma aplicação que possibilita plugins. ... 17

Figura 4. OSGi Service Registry. ... 19

Figura 5. Camadas do OSGi. ... 20

Figura 6. Hierarquia do Acrobat Core API. ... 25

Figura 7. A biblioteca para carregamento dinâmico ... 29

Figura 8. Exemplo de declaração da função CreateInstance. ... 30

Figura 9. Layout do OpenPaint. ... 32

Figura 10. Método OnMouse antes do refactoring. ... 33

Figura 11. Estrutura do padrão Command. ... 34

Figura 12. Representação resumida dos comandos. ... 36

Figura 13. Funcionalidade sem interação com o mouse. ... 37

Figura 14. OnMouse utilizando o padrão Command. ... 37

Figura 15. Extensão concreta. ... 40

Figura 16. Carregamento dos plugins. ... 41

Figura 17. Diagrama de seqüência demonstrando um clique no menu. ... 42

Figura 18. Método da classe ToolTriangle que desenha um triângulo na interface. . 43

Figura 19. Função de criação do plugin triângulo. ... 44

(11)

LISTA DE QUADROS

(12)

SUMÁRIO

1

INTRODUÇÃO ... 12

1.1 ESCOPO ... 12 1.2 OBJETIVO GERAL ... 13 1.3 OBJETIVOS ESPECÍFICOS ... 13

2

REVISÃO BIBLIOGRÁFICA ... 14

2.1 PLUGIN ... 14 2.2 OSGI ... 17

2.3 A TECNOLOGIA DE PLUGINS EM APLICAÇÕES COMERCIAIS ... 20

2.3.1 Eclipse ... 21

2.3.2 Mozilla Firefox ... 22

2.3.3 Internet Explorer ... 23

2.3.4 Adobe Reader ... 24

2.3.5 Aspectos dos plugins nos produtos ... 26

3

A APLICAÇÃO DO CONCEITO DE PLUGINS ... 28

3.1 A MODELAGEM DA BIBLIOTECA ... 28

3.1.1 A biblioteca em C++ ... 30

3.2 A ADAPTAÇÃO DE UM SISTEMA EXISTENTE... 31

3.2.1 O OpenPaint ... 31

3.2.2 Aspectos da arquitetura atual do OpenPaint... 32

3.2.3 Padrões de projetos ... 34

3.2.4 O conceito de plugins no OpenPaint ... 37

3.3 ESTENDENDO A APLICAÇÃO ... 42

3.3.1 Criando um plugin para a aplicação ... 42

4

CONCLUSÃO ... 45

REFERÊNCIAS ... 46

APÊNDICES ... 48

APÊNDICE A: DIAGRAMA DE CLASSE ILUSTRANDO AS INTERFACES UTILIZADAS NO REFACTORING (REFATORAÇÃO) DAS FUNCIONALIDADES ... 48

APÊNDICE B: DIAGRAMA DE CLASSES DEMONSTRANDO AS INTERFACES UTILIZADAS NA ARQUITETURA DE PLUGINS ... 49

APÊNDICE C: DIAGRAMA DE SEQÜÊNCIA DEMONSTRANDO O CARREGAMENTO DOS PLUGINS DURANTE O INÍCIO DA APLICAÇÃO ... 50

APÊNDICE D: CÓDIGO DO PROJETO TOOLTRIANGLE ... 51

APÊNDICE E: CÓDIGO DA APLICAÇÃO ... 54

APÊNDICE F: CÓDIGO DA BIBLIOTECA PLUGINCORE ... 86

APÊNDICE G: CÓDIGO DA BIBLIOTECA OPENPAINTAPI ... 92

APÊNDICE H: CÓDIGO DOS PLUGINS ... 95

(13)

1 INTRODUÇÃO

A utilização dos computadores cresceu nos últimos anos. Pesquisas informam que

no ano 2000 havia 10 milhões de computadores em uso no Brasil. Em 2009 esse

número cresceu para 60 milhões e estima-se que deva chegar em 100 milhões até o

ano 2012. Com o aumentado da utilização da informática, se ampliou também a

necessidade de aplicações das mais diversas áreas por parte dos usuários.

Devido ao baixo tempo de desenvolvimento requerido por parte dos clientes, iniciar a

implementação de um novo sistema do zero ou reescrever grande parte de um

software a cada nova necessidade torna quase que inviável o desenvolvimento de

software. Buscando aperfeiçoar o processo de desenvolvimento e aumentar a

qualidade e reutilização de código, a arquitetura dos sistemas evoluiu para um

design mais modularizado.

Outro ponto crítico na etapa de desenvolvimento está na manutenção de código.

Com o crescimento de um projeto, um código pouco modularizado e com alto

acoplamento tende a ser instável, já que a mudança de algum comportamento ou

correção de algum bug pode gerar efeito colateral em outra parte do sistema,

teoricamente não relacionada.

Além disso, a especificidade de uma funcionalidade necessária ao cliente pode

requerer que uma equipe especializada desenvolva parte do software.

Visando resolver esses problemas, o conceito de plugin ganhou força, possibilitando

que sistemas complexos possam ser compostos por componentes e equipes de

desenvolvimento formadas por terceiros possam implementar funcionalidades para a

aplicação.

1.1 Escopo

O escopo deste projeto delimita-se ao estudo da tecnologia de plugins, tendo como

exemplo aplicações reais. Uma aplicação será adaptada para utilizar plugins, com o

objetivo de demonstrar este conceito e comprovar seus benefícios.

(14)

1.2 Objetivo Geral

Apresentar a tecnologia de plugins, demonstrando suas vantagens e desvantagens

no desenvolvimento de software.

1.3 Objetivos Específicos

Os objetivos específicos são:

1. Estudar o conceito de plugins, utilizando publicações acadêmicas que

abordem o assunto;

2. Analisar algumas aplicações comerciais com suporte a plugins;

(15)

2 REVISÃO BIBLIOGRÁFICA

Este capítulo tem como objetivo realizar um estudo sobre a tecnologia de plugins.

Nele fazemos uma revisão da bibliografia acadêmica, apresentamos uma breve

introdução sobre OSGi (The Dynamic Module System for Java – Sistema Modular

Dinâmico para Java), quem vem se mostrando a principal iniciativa para criação de

aplicações com alto nível de modularização, e analisamos algumas aplicações

comerciais que utilizam esta tecnologia.

2.1 Plugin

Os plugins tem se popularizado nos últimos anos. Eles contribuíram para o sucesso

de aplicações conhecidas, como a IDE de desenvolvimento Eclipse e o navegador

de Internet Mozilla Firefox.

Esta tecnologia permite que sistemas sejam estendidos em tempo de execução

através da adição de uma nova funcionalidade. Por isso, ela é indicada para

sistemas que necessitam ser reconfigurados em tempo de execução e aplicações de

uso geral que estão em desenvolvimento.

Além disto, a utilização de plugins possibilita o desenvolvimento colaborativo de

aplicações. A aplicação principal pode definir pontos de extensão (extension points)

para adição de uma nova funcionalidade, permitindo que a equipe responsável pelo

desenvolvimento do projeto principal se concentre no núcleo (core) do produto e

outras equipes, formadas por terceiros ou não, trabalhem no desenvolvimento de

funcionalidades ou partes específicas do projeto. Adicionalmente, o fato de

diferentes equipes poderem desenvolver plugins alternativos para uma mesma

aplicação possibilita a competição entre esses fornecedores, o que tende a

aumentar a qualidade e a disponibilidade de plugins para uma determinada tarefa.

Segundo Dietrich et. al. (2007), os plugins podem ser classificados em duas

gerações. A principal diferença entre as gerações é que na primeira, apenas a

aplicação principal possui a habilidade de fornecer pontos de extensão. Já na

segunda geração, as extensões também possuem essa habilidade.

(16)

Figura 1. Diferença entre a primeira e segunda geração de plugins.

Fonte: Adaptação de Dietrich et al. (2007).

Mayer et al. (2002) apresentam o conceito de plugins através de um padrão de

projeto (design pattern), no formato dos designs patterns apresentados no livro

Design Patterns: Elements of Reusable Object-Oriented Software (Padrões de

Projetos: Soluções reutilizáveis de software orientado a objetos). Este padrão

permite que uma aplicação seja estendida em tempo de execução através de

módulos ou classes carregados dinamicamente, desconhecidos durante o tempo de

compilação. Ainda segundo Mayer et al. (2002), a estrutura do padrão seria formada

basicamente pelo plugin loader, pela interface do plugin e pelo plugin concreto,

como demonstrado na figura 2.

Figura 2. Diagram UML do padrão Plugin.

(17)

O plugin loader é a entidade responsável por procurar as extensões em tempo de

execução e dar ao cliente o acesso aos artefatos carregados. Já a interface PlugIn é

responsável por permitir a comunicação com todos os plugins concretos de um

mesmo tipo e determinar os métodos que o fornecedor do plugin deverá

implementar para que o mesmo funcione no sistema. Já a classe ConcretePlugin

implementa a interface PlugIn, fornecendo uma funcionalidade especial ao sistema.

Como motivação para o padrão, os autores citam o exemplo de uma aplicação

construída para exibir uma variedade de formatos gráficos, onde o desenvolvedor

não é capaz de escrever um decodificador (decoder) para um formato que será

definido após o desenvolvimento da aplicação. Este problema pode ser resolvido

permitindo que terceiros implementem plugins que recebam um stream codificado e

retornam um stream com a informação decodificada.

Dentre as vantagens da utilização de plugins na construção de uma aplicação, ficam

evidentes os seguintes benefícios:

1) Estender a aplicação durante a execução;

2) Modularizar sistemas volumosos a fim de reduzir a complexidade;

3) Desenvolver componentes do sistema sem ter que recompilar a aplicação

inteira;

4) Permitir que terceiros desenvolvam plugins;

5) Diminuir o tempo de startup e requisitos de hardware, como memória;

6) Permitir a reconfiguração de servidores sem necessidade de que os mesmos

sejam reiniciados.

Mas a utilização de plugins não apresenta apenas vantagens, segundo Marquart

(2005) algumas limitações podem ser encontradas no modelo, como:

1) Devem-se conhecer os tipos de extensões possíveis para a aplicação, pois as

interfaces devem ser definidas com antecedência;

2) A partir da hora que as interfaces são publicadas, o potencial de evolução da

aplicação fica limitado às classes e serviços que oferece;

(18)

3) Apenas a interface do plugin pode não ser suficiente para manter a aparência

(look-and-feel) da aplicação. Com isso, guias de estilo podem ser

necessários.

Se dividida em camadas, uma aplicação que tenha a capacidade de receber plugins

terá pelo menos as camadas das bibliotecas, do plugin loader (carregador de

plugin), das interfaces do plugin, da aplicação principal e dos plugins concreto,

conforme demonstrado na figura 3.

Figura 3. Camadas de uma aplicação que possibilita plugins.

Fonte: Mayer et al. (2002)

Nessa arquitetura, a aplicação principal conhece as camadas das interfaces de

plugins, do plugin loader e das bibliotecas. Já a implementação do plugin conhece

apenas a biblioteca e as interfaces dos plugins. Pode haver várias interfaces de

plugins, mas uma extensão concreta normalmente implementa apenas uma

interface. Dentro do código do plugin, as classes da biblioteca são usadas para

realizar tarefas comuns às extensões. Todas as funcionalidades adicionais são

fornecidas através de plugins e estes são gerenciados e carregados no sistema, em

tempo de execução, através do plugin loader. Todas as partes do sistema que não

podem ser modeladas como plugins devem pertencer à aplicação principal.

2.2 OSGi

Desde os anos setenta, a modularização do software é considerada como uma

propriedade chave para aumentar a flexibilidade e o reuso de projetos de software.

Geralmente, esses módulos podem ser considerados como unidades de trabalho

implementadas e compiladas independentemente da aplicação principal.

(19)

No caso de sistemas desenvolvidos em Java, esses módulos podem ser

constituídos de classes agrupadas na forma de pacotes e distribuídos em arquivos

JAR. Porém, essa abordagem pode apresentar dois problemas:

• As regras de visibilidade aplicadas às classes, atributos e métodos, como

público, protegido ou privado, não se aplicam ao nível de pacote e arquivo

JAR. Por exemplo, não é possível restringir o acesso a uma classe pública

definida em um pacote disponível. Isso faz com que outros módulos do

sistema tenham visibilidade desta classe, permitindo seu acesso e,

conseqüentemente, podendo aumentar o acoplamento entre módulos ou

camadas do software;

• Pela característica inerentemente estática da linguagem Java, existe a

necessidade da interrupção e reinício dos sistemas quando algum módulo é

atualizado.

Com o objetivo de resolver esses problemas, a OSGi Alliance propôs um modelo de

desenvolvimento e um framework que provê uma arquitetura dinâmica e orientada a

serviços para a plataforma Java. O núcleo da especificação é um framework que

define um modelo de gerenciamento de ciclo de vida, registro de serviços, ambiente

de execução e seus módulos.

De acordo com os princípios do OSGi, os sistemas devem ser estruturados através

de módulos, chamados de bundles, que disponibilizam serviços para a aplicação.

Através do gerenciamento do ciclo de vida dos bundles pelo framework, passou a

ser possível adicionar, remover e substituir bundles em tempo de execução.

Atualmente, a especificação do OSGi encontra-se na sua quarta revisão e possui

vários projetos que a implementam. Como exemplos, podemos citar:

• Implementações da quarta revisão: Knopflerfish, Apache Felix e Equinox;

• Implementação da terceira revisão: Concierge.

Basicamente, os bundles são arquivos JAR contendo arquivos “.class”, recursos

como ícones e imagens e um arquivo de manifesto que declara informações

estáticas a respeito do bundle, como os pacotes importados e exportados. Eles

(20)

devem fornecer serviços para outros bundles. Esses serviços são classes Java que

são registrados utilizando uma ou mais tipos de interface.

Para possibilitar que os serviços registrados sejam encontrados por outros bundles,

o OSGi define o Service Registry (registro de serviço) que fornece o meio necessário

para os bundles efetuarem a publicação e a recuperação de serviços. Como

demonstrado pela figura 4, a partir da hora que um serviço é publicado pelo bundle

A e um bundle B está procurando-o, o registro está apto a vincular estes dois

bundles.

Figura 4. OSGi Service Registry.

Fonte: Tavares e Valente (2008)

2.2.1 Arquitetura

Qualquer estrutura que implementa o padrão proposto pela OSGi Alliance fornece

um ambiente para a modularização da aplicação em pacotes menores.

Conceitualmente, na especificação do núcleo do OSGi, o framework é dividido nas

camadas Service, Life Cycle, Module, Execution Environment e Security, como

mostrado na figura 5.

(21)

Figura 5. Camadas do OSGi.

Fonte: OSGi Service Platform Core Specification.

Cada camada possui uma função bem definida:

• Service: a camada de serviços conecta bundles de uma forma dinâmica,

oferecendo um modelo baseado em publicar-procurar-vincular para objetos

Java. Possui o Service Registry, que fornece uma API para gerenciar

serviços. Ex: ServiceRegistration, ServiceTracker e ServiceReference;

• Life Cycle: fornece uma API para gerenciar o ciclo de vida dos bundles, que

podem estar nos estados instalar, iniciar, parar, atualizar e desinstalar;

• Module: é a camada que define o encapsulamento e declaração de

dependências. Define como um bundle pode importar e exportar código;

• Execution Environment: define quais os métodos e classes estão disponíveis

em uma plataforma específica. Não existe uma lista fixa de ambientes de

execução, uma vez que está sujeita a criação de novas versões e mudanças

nas edições do Java, realizado pela Java Community Process;

• Security: é a camada que lida com aspectos de segurança, limitando as

funcionalidades dos bundles a capacidades pré-definidas.

2.3 A Tecnologia de Plugins em Aplicações Comerciais

Nesta seção demonstraremos alguns aspectos da utilização de plugins por

aplicações conhecidas e largamente utilizadas no dia-a-dia. Procuraremos abordar

sistemas de diferentes áreas, como plataformas de desenvolvimento de software,

navegadores de Internet e visualizadores de PDF.

(22)

Para este estudo, priorizamos aplicativos que possuem algum tipo de documentação

disponível ou publicações em artigos e livros. Levando em consideração esta

premissa, escolhemos a IDE de desenvolvimento Eclipse, os navegadores de

Internet Mozilla Firefox e Internet Explorer e a ferramenta para visualização de

arquivos PDF Adobe Reader.

Ao final, faremos algumas considerações sobre as aplicações estudadas com

relação ao uso de plugins.

2.3.1 Eclipse

O Eclipse não é um simples programa monolítico. Ele é formado por um pequeno

kernel (núcleo) cercado por centenas de plugins. Este pequeno kernel é uma

implementação da especificação OSGi R4 e recebeu o nome de Equinox.

Devido ao seu design modularizado, o Eclipse possibilita criar extensões que não

foram previstas pelos desenvolvedores originais da aplicação. O conjunto mínimo de

plugins para formar uma aplicação cliente é chamado de Eclipse Rich Client Platform

(RCP).

Todo o comportamento dos plugins é definido no código e suas dependências e

serviços são declarados nos arquivos MANIFEST.MF e plugin.xml.

No início da aplicação, o plugin loader lê os arquivos MANIFEST.MF e plugin.xml de

todos os plugins, formando a estrutura definida nesses arquivos. Isso consome

memória, mas permite que os plugins sejam encontrados mais rapidamente quando

requeridos e reduz a quantidade de memória consumida pelo sistema se comparado

com o carregamento da aplicação e do código de todas as extensões de uma única

vez.

Um típico plugin para o Eclipse deve incluir os arquivos Java (com extensão .class),

imagens e ícones utilizados pelo plugin, o arquivo MANIFEST.MF descrevendo

aspectos do plugin como identificador, versão e dependências, e o arquivo

plugin.xml descrevendo a extensão e seus pontos de extensão.

Um plugin pode ser adicionado ao Eclipse de três formas:

(23)

2 Criando um sítio de update do Eclipse (Eclipse Update Site), permitindo que o

Eclipse baixe e gerencie o plugin a partir deste site;

3 Instalando o plugin em outro diretório e criando um arquivo de link para que o

Eclipse encontre as extensões. Para isso, um arquivo no formato “.link” deve

ser colocado na pasta links do Eclipse. Se o subdiretório links não existir, ele

deverá ser criado.

2.3.2 Mozilla Firefox

Os plugins para o Firefox, também conhecidos como extensões ou add-ons, podem

acessar os recursos do navegador e melhorar suas funcionalidades.

O Mozilla oferece uma técnica fácil e flexível de criar plugins. Toda extensão do

Firefox é definida em um arquivo XPI (Cross-Platform Install), que é compatível com

o formato Zip. Neste arquivo encontramos o código da extensão, assim como o

arquivo “install.rdf”, que possui as informações de instalação. As principais

informações contidas no arquivo “install.rdf” são: o nome da extensão, a versão

compatível do navegador e um número único de identificação. O responsável por

gerenciar as extensões do navegador é chamado de Extension Manager (EM –

Gerente de Extensão).

Todas as extensões para o Firefox são escritas em Javascript. Quando uma

extensão é executada, ela é interpretada pela engine (motor) Mozilla Javascript que

é embutida dentro do navegador. Por serem escritos em Javascript, os plugins do

Firefox são de código aberto por definição.

Ao criar extensões, o desenvolvedor deve tratar os eventos criados pelo navegador.

Esses eventos são normalmente criados em resposta a uma entrada do usuário ou

ao final do carregamento de uma página Web. Por exemplo, o desenvolvedor

poderá interceptar as teclas pressionadas pelo usuário tratando os eventos de clique

no teclado (key-press events). Também é possível mudar o conteúdo de uma página

alterando sua representação interna (DOM – Document Object Model).

Se uma extensão possuir interface com o usuário, ela deverá utilizar a linguagem

XML User Interface Language (XUL – Linguagem XML de Interface de Usuário). O

XUL é um dialeto XML (Extensible Markup Language – Linguagem de Marcação

(24)

Extensível) interpretado pelo motor de renderização Gecko, que apresenta a GUI

dentro do navegador.

2.3.3 Internet Explorer

Os plugins para o navegador Internet Explorer (IE) são integrados com a aplicação

através do desenvolvimento de um objeto BHO (Browser Helper Object). Esses

objetos possuem acesso ao mecanismo de evento do IE e possibilitam a criação de

elementos da interface com o usuário.

Os objetos BHOs são objetos binários que seguem o padrão COM (Component

Object Model – Modelo de Objeto Componente). Este padrão foi desenvolvido pela

Microsoft para apoio, entre outras coisas, ao mercado de softwares baseados em

componentes. Todo objeto COM implementa um conjunto de interfaces, sendo cada

interface um contrato bem definido que descreve a sua funcionalidade. O padrão

COM garante que as tabelas virtuais das interfaces continuam as mesmas

independentemente

de

compilador,

permitindo

a

esses

objetos

serem

implementados e utilizados por qualquer linguagem que suporte chamadas de

funções através de uma tabela de ponteiros de função.

O BHO é um simples objeto COM que implementa a interface IObjectWithSite. Os

elementos da interface com o usuário são similares aos objetos BHO, sendo que

implementam mais algumas interfaces e incluem um componente gráfico.

Ao

iniciar,

o

Internet

Explorer

consulta

a

chave

de

registro

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser

Helper

Objects e carrega todos os objetos que possuem identificador salvos lá. Logo após,

o IE fornece para cada BHO um ponteiro para a interface IUnkown. Através deste

ponteiro o objeto BHO pode consultar o IE sobre interfaces mais específicas, como

IWebBrowser2, IDispatch ou IConnectionPointContainer, tornando possível acessar

eventos e funções do navegador.

Como os objetos BHO são executados como código nativo dentro do processo do

browser, ele poderá acessar aos recursos do sistema operacional que o navegador

tem acesso, como sockets, arquivos e processos da rede.

(25)

2.3.4 Adobe Reader

Para auxiliar na criação de plugins para o Adobe Reader, a Adobe disponibiliza um

kit de desenvolvimento de software (SDK – Software Development Kit) chamado

Acrobat SDK. O Acrobat SDK possui duas bibliotecas, a Acrobat core API e a PDF

Library API. A Acrobat core API contém um conjunto de interfaces que permite ao

desenvolvedor interagir com o Adobe Reader. Já a PDF Library API possibilita que

os desenvolvedores interajam e manipulem arquivos PDF.

Os plugins adicionam uma nova funcionalidade e são equivalentes às bibliotecas

lincadas dinamicamente (DLL) na plataforma Windows, com a diferença de que a

extensão da biblioteca não é “.dll”, mas sim “.api”. No sistema operacional Mac OS a

extensão do nome do plugin é acroplugin.

Os plugins desenvolvidos são colocados na pasta plug-ins no diretório do Acrobat e

após a inclusão de uma nova extensão, o aplicativo deve ser reiniciado para que o

plugin seja reconhecido.

2.3.4.1

Acrobat core API

A Acrobat core API consiste em métodos que operam sobre os objetos contidos

dentro do documento PDF. Ela é implementada como uma biblioteca ANSI C e é

suportada no Windows (32 bits), Mac OS, Linux, alguma plataformas UNIX, como o

Solaris, HP-UX e AIX.

(26)

Figura 6. Hierarquia do Acrobat Core API.

Fonte: Adobe Acrobat SDK 8.1

A camada Acrobat Viewer (AV) possibilita ao plugin controlar e modificar a interface

com o usuário. Através desta camada, utilizando os métodos AV, é possível

adicionar menus, botões, abrir e fechar arquivos e exibir caixas de diálogo.

A camada Portable Document (PD) fornece acesso aos componentes do documento

PDF, como as páginas e anotações. Nesta camada existem dois grupos de métodos

que controlam diferentes aspectos do documento. Os métodos PDFEdit lidam com a

representação física do documento PDF e permitem aos plugins ler, escrever, editar

e manipular recursos de uma página, como fontes e imagens. Os métodos PDSEdit

lidam com a estrutura lógica do documento, permitindo ao plugin acessar um arquivo

PDF através de uma estrutura de árvore, facilitando a navegação, procura e

extração de dados de um documento PDF.

A camada Acrobat Support (AS) fornece uma variedade de métodos utilitários, como

rotinas de alocação de memória. Além disso, permite ao plugin substituir rotinas de

baixo nível do sistema de arquivos utilizadas pelo Acrobat, como ler, escrever,

reabrir, remover, renomear, entre outras. Isso permite que o Acrobat seja utilizado

em outros sistemas de arquivos, como no caso de sistemas on-line.

A camada Cos Object System (Cos) fornece acesso aos blocos de construção

utilizados na criação de documentos PDF. Ela permite manipular dados de um

arquivo PDF num baixo nível, como um dicionário ou um stream (fluxo) de dados.

(27)

Além dos métodos apresentados anteriormente, a Acrobat core API fornece um

grupo de métodos para lidar com questões que são único nas plataformas Windows,

Linux e Mac OS.

2.3.5 Aspectos dos plugins nos produtos

Com o estudo realizado sobre as aplicações comerciais, encontramos alguns

aspectos importantes que complementam o conceito de plugins e ajudam a tornar

um software extensível.

Notamos que um software "plugável" pode ter dois tipos de arquitetura. No primeiro

tipo, todas as partes do software são providas através de plugins e um framework de

aplicação administra as extensões e suas interações. No segundo, a aplicação já

possui suas funcionalidades pré-definidas e publica alguns pontos de extensão que

possibilitam criar plugins para o software.

Para que a aplicação seja capaz de encontrar os plugins em tempo de execução, é

necessário definir a forma como essas extensões serão descobertas. Aplicações

como Adobe Reader e Firefox disponibilizam uma pasta onde todas as extensões

para a aplicação devem ser armazenadas. Já o Eclipse, além da opção de

armazenar os plugins em uma pasta pré-definida, também permite que eles sejam

instalados em outra pasta, necessitando que a localização seja informada em um

arquivo em formato específico (.link). O Internet Explorer, por sua vez, utiliza o

registro do Windows para localizar os plugins instalados.

Quanto ao formato do arquivo do plugin, não existe uma padronização. Esse formato

é influenciado diretamente pelas características de cada linguagem de programação

e pelo fabricante do software. No caso de plugins que são interpretados, os scripts

podem ser agrupados em um arquivo semelhante a um arquivo compactado e

utilizados de acordo com a necessidade da aplicação. Quanto aos plugins

compilados, os formatos DLL, COM e JAR são os mais utilizados, sendo este último

especifico para a linguagem Java. Apesar das diferenças de formato de arquivo,

todas as extensões possuem basicamente o mesmo conteúdo. São formadas pelas

classes ou funções (compiladas ou para interpretação) que estendem as interfaces

publicadas, recursos como figuras e ícones e, em alguns casos, arquivos que

descrevam características dos plugins.

(28)

Por último, vimos que é comum as aplicações disponibilizarem bibliotecas ou SDKs

(Software Development Kit – Kit de Desenvolvimento de Software), além das

interfaces para extensão, para facilitar o desenvolvimento dos plugins, melhorando a

integração entre extensão e software estendido.

(29)

3 A APLICAÇÃO DO CONCEITO DE PLUGINS

Este capítulo tem como objetivo demonstrar a adaptação de uma aplicação legada

para a utilização de plugins. Para tal, modelamos uma biblioteca que facilita o

carregamento dinâmico de classes, refatoramos uma aplicação para uma arquitetura

intermediária e aplicamos o conceito de plugins. Ao final, apresentamos uma forma

de criar novas extensões para a aplicação.

3.1 A Modelagem da Biblioteca

Com base nos estudos realizados no capítulo anterior, modelamos uma biblioteca

que possibilita estender softwares em tempo de execução. Ela segue o padrão

proposto por Mayer et. al. (2002), onde é prevista a utilização de interfaces para os

plugins, um carregador de plugins e extensões concretas.

Antes de iniciar a modelagem, determinamos algumas premissas que nortearam o

desenvolvimento. De acordo com essas premissas, a biblioteca deve:

1) Disponibilizar uma interface comum aos plugins, pois toda comunicação entre

aplicação e extensão será realizada através desta interface;

2) Prover um mecanismo de carregamento dinâmico de plugins, que carregará

as extensões a partir de um determinado diretório;

3) Possibilitar que as extensões sejam carregadas apenas quando solicitadas.

Com esses objetivos levantados, desenvolvemos a arquitetura apresentada na figura

7.

(30)

Figura 7. A biblioteca para carregamento dinâmico

Essa

biblioteca

é

formada

pela

interface

IPlugin

e

pelas

classes

PluginInstance

,

PluginLoader

e

FileScan

.

A interface

IPlugin

é a base da hierarquia dos plugins e declara apenas o método

abstrato

GetPluginName

. Ela se torna o ponto de comunicação entre a biblioteca

do plugin concreto e a estrutura responsável por carregar as extensões. No domínio

da biblioteca modelada, nenhuma outra interface de plugin é conhecida. A

especialização da interface

IPlugin

deve ser concebida pela aplicação ou

framework sobre o qual a aplicação é implementada. O método

GetPluginName

deve ser implementado pelo plugin concreto, onde informará o nome da extensão.

Essa informação poderá ser utilizada para apresentar ao usuário o nome da

extensão carregada.

A classe

PluginInstance

é a classe responsável por encapsular o caminho da

biblioteca do plugin instalada e uma referência para a instância do plugin. Os

métodos

Init

e

Stop

permitem alocar e desalocar a instância de um plugin,

fazendo com que a extensão não tenha que estar em memória durante todo o tempo

de vida da aplicação.

(31)

Junto com

PluginInstance

, a classe

PluginLoader

é responsável por executar

o carregamento dinâmico dos plugins. Ao disponibilizar os métodos

GetPlugin

e

GetPlugins

, a classe possibilita ao cliente passar o caminho de um único plugin ou

o caminho do diretório onde estão todas as extensões. Para encontrar os caminhos

dos plugins em um diretório, o

PluginLoader

utiliza a classe utilitária

FileScan

.

3.1.1 A biblioteca em C++

Com o projeto da biblioteca conceitualmente modelado, desenvolvemos sua versão

para C++. Os seguintes aspectos motivaram a escolha da linguagem:

1) O sistema proposto para ser adaptado à tecnologia de plugins é desenvolvido

em C++;

2) O conhecimento da linguagem pelo autor.

Essa biblioteca foi desenvolvida na forma de uma biblioteca estática (.lib) e deve ser

utilizada incluindo os arquivos de cabeçalhos das classes (.h) dentro do código da

aplicação e lincando a biblioteca ao executável após a compilação do sistema.

Na linguagem C++, as extensões concretas devem ser compiladas no formato de

DLL (dynamica-link library ou biblioteca de ligação dinâmica). Por este motivo, toda

extensão deve exportar a função

CreateInstance

, possibilitando a aplicação ler a

DLL e criar os plugins. Esta função deve retornar um ponteiro com um plugin

alocado. A figura 8 ilustra como que a função

CreateInstance

é declarada.

(32)

Para o carregamento das DLLs, as funções da API do Windows

LoadLibrary

,

GetProcAddress

e

FreeLibrary

foram utilizadas. A plataforma UNIX também

possui funções equivalentes às do Windows, o que possibilita que essa biblioteca

seja portada para outros sistemas operacionais além do Windows. Apresentamos na

tabela 1 as equivalências entre as funções para manipulação de bibliotecas

dinâmicas no Windows e no Unix.

Quadro 1 - Equivalências entre API do Windows e do UNIX.

API do Windows

API do UNIX

Cabeçalho das funções

windows.h

dlfcn.h

Função para carregar

LoadLibrary

LoadLibraryEx

dlopen

Função para extrair

conteúdo

GetProcAddress

dlsym

Função para

descarregar

FreeLibrary

dlclose

Para auxiliar no desenvolvimento, um projeto de teste foi formado. Nele, foram

criados testes unitários que garantem os objetivos descritos no início deste capítulo.

Além deste projeto, duas DLLs que implementam a classe

IPlugin

foram criadas

para tornar possível a realização dos testes sem depender da aplicação principal.

3.2 A Adaptação de um Sistema Existente

Este capítulo tem como objetivo descrever a adaptação de uma aplicação real,

desenvolvida em C++, para utilizar o conceito de plugins estudado nos capítulos

anteriores.

Na primeira parte deste capítulo, apresentaremos o sistema que será adaptado,

assim como aspectos da sua arquitetura. Logo após, abordaremos o padrão de

projeto que auxiliou na refatoração (refactoring) da aplicação para uma arquitetura

intermediária, de modo a facilitar a adaptação para a arquitetura proposta. Por fim,

demonstraremos a aplicação da tecnologia de plugins ao sistema, descrevendo as

interfaces criadas, os plugins concretos, o carregamento e a ativação dos plugins.

3.2.1 O OpenPaint

O sistema escolhido para aplicar o conceito de plugins se chama OpenPaint. Ele é

um editor de imagens open source com funcionalidades semelhantes às do Paint,

(33)

editor de imagens distribuído com as versões do sistema operacional Microsoft

Windows. A figura 9 apresenta o layout do OpenPaint.

Figura 9. Layout do OpenPaint.

Fonte: openpaint.org

Entre seus recursos, o OpenPaint apresenta:

• Layout familiar;

• Suporte a múltiplas abas;

• Suporte a um grande número de tipos de imagens;

• Ferramentas como lápis, pincel, borracha, ampliação, seleção, entre outros;

• Opções para escalonar, redimensionar, girar e espelhar as imagens;

• Filtros de imagens.

O OpenPaint é um sistema implementado em C++, utilizando o toolkit gráfico open

source chamado wxWidgets. Sua arquitetura não é divida em camadas e suas

classes são grandes. Na próxima seção abordaremos aspectos da arquitetura do

OpenPaint.

3.2.2 Aspectos da arquitetura atual do OpenPaint

O OpenPaint não é um sistema dividido em camadas. Todas as funcionalidades da

aplicação são implementadas dentro da classe

OpenPaintMDIChildFrame

, que é

(34)

o frame responsável pelo desenho. Suas funcionalidades podem ser classificadas

em dois tipos:

• Funcionalidades que executam apenas uma operação e são finalizadas.

Como exemplo, podemos citar a aplicação de filtro em uma imagem;

• Funcionalidades que reagem aos eventos do mouse, executando

transformações na área de desenho. Como exemplo, temos as funções de

pintar e apagar.

Para cada funcionalidade do primeiro tipo, a classe

OpenPaintMDIChildFrame

fornece um método público, que é executado quando o cliente clica em um menu da

interface gráfica. Já para as funcionalidades que reagem aos eventos do mouse, a

classe implementa o método OnMouse que, através das instruções de controle

condicional

if/else

e

switch

, executa a função requisitada. Abaixo,

apresentamos um fragmento do método

OnMouse

.

Figura 10. Método OnMouse antes do refactoring.

Com essa estrutura, a classe

OpenPaintMDIChildFrame

precisa ser alterada

a

cada inclusão de nova funcionalidade, aumentando ainda mais o seu tamanho e a

complexidade do método

OnMouse

.

(35)

Outro aspecto negativo da estrutura do OpenPaint é o fato da aplicação ser

implementada dentro da interface gráfica. Com a atual abordagem, qualquer

alteração feita no sistema pode impactar em outras áreas da aplicação, além de

inviabilizar a inclusão de testes unitários de maneira significante.

3.2.3 Padrões de projetos

Por causa da falta de modularidade do OpenPaint, antes de começar a aplicar o

conceito de plugins, precisamos isolar as funcionalidades que se encontram

implementadas no frame de desenho em estruturas genéricas. Para isso, aplicamos

o padrão Command (comando), criando uma hierarquia de classes que reflita as

necessidades da aplicação.

3.2.3.1

O padrão Command

De acordo com Gamma et. al. (1995), o padrão Command tem como objetivo

“encapsular uma solicitação como um objeto, desta forma permitindo parametrizar

clientes com diferentes solicitações, enfileirar ou fazer registros (log) de solicitações

e suportar operações que podem ser enfileiradas”. Desta forma, todas as

solicitações compartilham uma interface em comum, permitindo que todas sejam

invocadas da mesma maneira. A estrutura do padrão é apresentada na figura 11.

Figura 11. Estrutura do padrão Command.

Fonte: Gamma et. al., 1995

Na estrutura definida por Gamma et. al. (1995), os participantes do padrão possuem

as seguintes responsabilidades:

(36)

• Command: classe abstrata ou interface que declara uma operação que será

implementada pelas suas classes filhas;

• ConcreteCommand: é o objeto concreto de Command que implementa o

método Execute. Pode vincular o Receiver a uma ação;

• Client: cria os objetos ConcreteCommand. Num sistema real, pode ser a

própria aplicação;

• Invoker: solicita ao Command a execução da solicitação;

• Receiver: sabe como executar as operações associadas a uma solicitação.

Gama e. al. (2005) ainda discutem o quanto de inteligência um comando deve ter,

sendo que a implementação do padrão pode variar numa gama de possibilidades.

Em sua forma mais simples, o padrão Command pode servir apenas como vínculo

entre uma ação e um Receiver. Em outro extremo, o padrão implementa toda a

lógica, sem delegar nenhuma tarefa ao Receiver.

A aplicação do padrão Command desacopla o objeto que chama uma função do

objeto responsável em realizá-la, além de facilitar a adição de novos comandos à

aplicação.

3.2.3.2

A aplicação do padrão

Um dos problemas para aplicar o conceito de plugins no OpenPaint é a falta de

abstrações que encapsulem as funcionalidades do sistema. Como foi observado em

seções anteriores, a classe

OpenPaintMDIChildFrame

é responsável pela

implementação das funcionalidades e a execução é realizada no método OnMouse.

Toda execução é orientada através de uma grande lógica condicional if/else

aninhada a um switch.

Em Refactoring to Patterns (Refatorando para Padrões), Kerievsky (2008) sugere

que a lógica condicional utilizada para executar ações seja substituída pelo padrão

Command, quando:

(37)

• Existe pouca flexibilidade em tempo de execução, onde os clientes dependem

de um mecanismo de envio condicional e não podem configurá-lo

dinamicamente;

• O corpo dos mecanismos de lógica condicional se torna grande.

Desta forma, refatoramos as funcionalidades para classes que estendam as

interfaces IMenuCommand e IToolCommand. As interfaces dos comandos estão no

Apêndice A e uma representação resumida é demonstrada na figura 12.

Figura 12. Representação resumida dos comandos.

As interfaces dos comandos foram divididas em duas, IToolCommand e

IMenuCommand, devido ao fato da aplicação já tratar de forma diferente as

funcionalidades que necessitam interação com o mouse das que não necessitam.

A interface IMenuCommand é implementada nos casos das funcionalidades que

executam uma ação sobre a área de desenho, sem necessitar de interação do

mouse. Assim, ela é ativada e utilizada apenas no escopo do método que trata os

eventos de menu. O trecho de código abaixo ilustra a sua utilização.

(38)

Figura 13. Funcionalidade sem interação com o mouse.

Já nos casos dos comandos que necessitam de interação com o mouse, foi utilizada

a estratégia de manter o comando ativado pelo usuário em uma variável de instância

chamada

comandoAtual

. Ou seja, quando o usuário clicar em um comando que

necessite interação com o mouse, como no caso de pintar, o comando escolhido

será atribuído como comando atual da aplicação e, a partir desse momento, o

método OnMouse delegará ao comando o tratamento das solicitações do usuário,

como ilustrado no trecho de código abaixo.

Figura 14. OnMouse utilizando o padrão Command.

3.2.4 O conceito de plugins no OpenPaint

Com a extração das funcionalidades da aplicação

em comandos, o processo de

adaptação do sistema para aceitar plugins foi facilitado. Porém, nesta versão do

OpenPaint, possibilitaremos apenas a criação de plugins da primeira geração, ou

seja, apenas a aplicação disponibilizará pontos de extensão. Isto se deve ao fato do

atual design do sistema ser pouco orientado a objetos, não possuindo real divisão de

suas camadas.

(39)

Para identificar quais são os possíveis candidatos a plugin em uma aplicação,

Marquart (2005) sugere verificar os pontos em aberto na especificação da

aplicação. Frequentemente, um tipo de extensão pode estar implicita em frases da

especificação que possuem a palavra “etc”. Subclasses de uma abstração chave

também são candidatas, quando se tem interesse em extender o sistema

adicionando outras subclasses. Desta forma, no OpenPaint todas as funcionalidades

disponíveis na interface gráfica para o cliente são candidatas a se tornarem

extensões.

Seguindo a arquitetura proposta por Mayer et al. (2002), detalharemos nas próximas

subseções a construção das interfaces dos plugins, dos plugins concretos e do

PluginLoader.

3.2.4.1

Interfaces dos plugins

De acordo com o conceito de plugins, as interfaces são as responsáveis por

possibilitar a comunicação entre a aplicação e suas extensões.

No caso do OpenPaint, apenas as funções disponíveis no menu e na barra de

ferramentas do sistema se tornaram plugins. Assim, as interfaces dos comandos

descritas em seções anteriores foram aproveitadas, com pequenas alterações.

Como descrevemos nos capítulos anteriores, a aplicação deve especializar a

interface

IPlugin

, criando novas interfaces de extensão. Para viabilizar a

comunicação entre a aplicação e os plugins, criamos as seguintes interfaces:

• IToolPlugin: estende a interface IPlugin, permitindo o tratamento dos eventos

do mouse MouseDown (início do clique do mouse), MouseMove (movimento

do mouse sobre o frame) e MouseUp (fim do clique do mouse) sobre a área

de desenho;

• IMenuPlugin: estende a interface IPlugin, possibilitando executar ações no

frame de desenho, sem que haja interação com o mouse;

• IPaintPainel: essa interface encapsula as principais operações realizadas em

cima do frame de desenho. Toda alteração na área de desenho é realizada

através desta interface;

(40)

• ISelectionAttributes: essa interface é acessada através da interface

IPaintPainel e possui informações a respeito de seleção realizada na área de

desenho.

Apresentamos no Apêndice B o diagrama de classes descrevendo as interfaces

apresentadas acima.

Para melhorar a organização do projeto da aplicação, as interfaces foram extraídas

para um novo projeto chamado OpenPaintAPI, onde os desenvolvedores da

aplicação e dos plugins compartilham a mesma biblioteca. Em aplicações melhores

estruturadas, essas interfaces seriam candidatas a fazer parte de um framework da

aplicação.

3.2.4.2

Os plugins concretos

Os plugins concretos são implementações das interfaces publicadas pelo OpenPaint

e necessitam ser carregados de forma dinâmica. Em C++, o modo de realizar esse

carregamento dinâmico é através da utilização de DLLs. A DLL (Dynamic-link Library

ou biblioteca de ligação dinâmica) é uma implementação feita pela Microsoft que

contem código executável, dados e recursos.

Com a lógica das funcionalidades encapsuladas em comandos, bastou criar um

projeto de DLL para cada funcionalidade, corrigindo as diferenças existentes entre

as interfaces dos comandos e dos plugins. Os requisitos mínimos dos projetos são:

• Arquivo que define o ponto de entrada da DLL. Geralmente é nomeado como

dllmain.cpp;

• Arquivo com a implementação do plugin;

• Arquivo com a função de criação do plugin. É esta função que é exportada

junto com a DLL e que é utilizada pela aplicação para carregar o plugin.

Abaixo, mostramos o código gerado pela implementação de uma extensão da

interface IMenuPlugin.

(41)

Figura 15. Extensão concreta.

Para a aplicação, a única função conhecida é a função

CreateInstance,

sendo

que todas as implementações de plugins devem exportar esta função.

3.2.4.3

O carregamento dos plugins

As DLLs dos plugins devem ser colocadas na pasta plugins, dentro do diretório da

aplicação. Durante o início do sistema, todas as DLLs são lidas, com a finalidade de

criar uma estrutura interna para montar a interface gráfica.

Para realizar a leitura das extensões, a aplicação deve utilizar a classe

PluginLoader

, informando a pasta onde os plugins estão armazenados e a

extensão do arquivo da biblioteca dinâmica. Como retorno, a aplicação recebe um

vetor de plugins que são utilizados para construir a interface gráfica. A figura 16

mostra como que os plugins são carregados.

(42)

Figura 16. Carregamento dos plugins.

Ainda durante o carregamento dos plugins, cada extensão é armazenada dentro de

um mapa, através da chamada do método

setPlugins

. Cada extensão recebe um

identificador único, que será utilizado para ativação do plugin, após o mesmo ser

escolhido na interface gráfica pelo usuário. O Apêndice C apresenta o diagrama de

seqüência com as interações realizadas durante o carregamento dos plugins, assim

que a aplicação é iniciada.

3.2.4.4

A ativação de um plugin

Como vimos na seção anterior, cada plugin recebe um identificador único ao ser

carregado. Esse identificador é utilizado para criar a correspondência dos menus e

das ferramentas de desenho na interface gráfica, sendo que cada componente

gráfico recebe o identificador do plugin que o corresponde.

Na figura 17, percebemos que quando o usuário clica em um componente da

interface gráfica, um evento é disparado delegando a classe

OpenPainCtrl

o seu

tratamento. Na classe

OpenPaintCtrl

, o plugin é localizado através de seu

identificador único e seu algoritmo executado.

(43)

Figura 17. Diagrama de seqüência demonstrando um clique no menu.

No caso de ferramentas de desenho, a diferença está no fato de que o plugin não é

executado e sim atribuído como plugin atual da aplicação. Desta forma, todos os

eventos de

MouseDown

,

MouseMove

e

MouseUp

que acontecem na janela de

desenho são delegados ao plugin.

3.3 Estendendo a Aplicação

Após a refatoração e a adaptação da aplicação, o OpenPaint se tornou um sistema

possível de extensão através da criação de novos plugins. Para tanto, as novas

extensões devem implementar as interfaces

IToolPlugin

ou

IMenuPlugin

e

compilá-las no formato de uma DLL, exportando a função de criação

CreateInstance

.

A seguir, demonstraremos a criação de uma ferramenta de desenho para aplicação.

3.3.1 Criando um plugin para a aplicação

Para iniciar, devemos levantar o que a ferramenta proposta deve realizar. Como

pré-requisitos, definimos que a ferramenta necessita:

• Possibilitar ao usuário desenhar um triângulo vazado na janela de desenho

com um único clique;

(44)

• Utilizar a cor definida pelo usuário na paleta de cores para desenhar o

contorno do triângulo.

Com os objetivos da ferramenta definidos, o próximo passo é criar um projeto

console no Visual C++, informando o tipo de aplicação como DLL. Automaticamente,

o Visual C++ cria os arquivos necessários para o projeto. No caso do nosso plugin, o

nome dado ao projeto foi

ToolTriangle

.

Após a criação do projeto, foi necessário configurá-lo. Para isso, precisamos

informar ao projeto as pastas com os arquivos de cabeçalho (extensão “.h”) das

interfaces e das bibliotecas utilizadas para auxiliar na criação de plugins, como o

PluginCore

e a

OpenPaintAPI

. Além dessas, também foi necessário incluir a

biblioteca

wxWidgets

, que é o toolkit gráfico utilizado pela aplicação, tanto para

criação da interface gráfica com o usuário quanto para as estruturas de dados, como

exemplo do mapa de bits.

Na figura abaixo, demonstramos o algoritmo utilizado para desenhar um triângulo na

área de desenho. Nele, definimos os três pontos do triângulo a partir do seu centro,

e utilizamos a classe

wxMemoryDC

para desenhar o triângulo no bitmap atual. Ao

final, informamos ao painel de pintura a imagem atualizada.

Figura 18. Método da classe ToolTriangle que desenha um triângulo na interface.

Para que a extensão seja encontrada pela aplicação, é necessário declarar e

exportar a função que cria o plugin. Na figura 19 apresentamos está função.

(45)

Figura 19. Função de criação do plugin triângulo.

Como resultado, o usuário encontrará um triângulo na paleta e no menu Tools. Ao

clicar na ferramenta, o usuário poderá desenhar com um único clique um triângulo

que contem as cores escolhidas em seu contorno. A figura 20 mostra o resultado

visual na aplicação e o Apêndice D apresenta o código completo do plugin.

(46)

4 CONCLUSÃO

Podemos verificar que a tecnologia de plugins é observada pela indústria de

desenvolvimento de software como uma alternativa para flexibilizar a extensão de

aplicações. Vários sistemas de diferentes domínios estão utilizando esta arquitetura.

Esta

abordagem

possibilita

que

outros

desenvolvedores

implementem

funcionalidades para softwares que já estão em utilização, tornando plausível o

desenvolvimento colaborativo de software.

Do ponto de vista de utilização de hardware, esse padrão de projeto otimiza o uso

de memória, uma vez que o sistema não é carregado inteiro para a memória de uma

única vez, além de tornar mais rápido o carregamento (startup) dos programas.

Quanto ao processo de desenvolvimento de software, sua utilização pode diminuir

os tempos de compilação, já que não existe a necessidade da compilação da

aplicação inteira, tornando o desenvolvimento mais rápido.

Em alguns casos, o esforço de desenvolvimento pode aumentar. Como foi visto na

aplicação OpenPaint, seu código teve que ser refatorado para poder começar a

utilizar plugins, sendo que não chegou a um nível ideal. Inevitavelmente, somente a

tecnologia de plugins não garante a qualidade do código do software.

Além disso, verificamos que a aplicação deve possuir uma política de controle de

versão de plugins, evitando conflitos entre a aplicação e extensões. Uma forma de

gerenciar como os plugins são apresentados na interface gráfica também é

necessária, já que a inclusão de plugins na mesma ordem em que são lidos podem

não refletir a necessidade do cliente.

Outro ponto que não foi abordado no sistema, mas merece atenção, é a segurança

da aplicação quando oferece pontos de extensão. À primeira vista, a aplicação pode

se tornar mais vulnerável para debbuggers quando existem pontos de extensão. Isso

pode ser crucial em aplicações de código fechado.

(47)

REFERÊNCIAS

Adobe Acrobat SDK 8.1 Developing Plug-ins and Applications for Microsoft

Windows,

Mac

OS,

Linux

and

UNIX.

Disponível

em:

<

http://www.adobe.com/devnet/acrobat/pdfs/plugin_apps_developer_guide.pdf>.

Acessado em 19/06/2009.

CLAYBERG, E., RUBEL, D. Eclipse Plug-ins. 3 ed. Addison Wesley.2008.

DIETRICH, Jens; HOSKING, John; GILES, Jonathan. A Formal Contract Language

for Plugin-based Software Engineering. In: Proceedings of the 12th IEEE

international Conference on Engineering Complex Computer Systems (July 11 - 14,

2007). ICECCS. IEEE Computer Society, Washington, DC, 175-184.

GAMMA, E., HELM, R., JOHNSON, R., VLISSIDES, J. Design Patterns: Elements of

Reusable Object-Oriented Software. Addison-Wesley. 1995.

KERIEVSKY, J. Refatoração para padrões. Porto Alegre: Bookman, 2008.

MARQUARDT, K. Patterns for plug-ins. In: MANOLESCU, D.; VOELTER, M.;

NOBLE, J. Pattern Language of Program Design 5. Boston: Addison Wesley, 2006.

Cap. 12. p. 301 – 335.

MAYER, Johannes; MELZER, Ingo; SCHWEIGGERT, Franz. Lightweight

Plug-in-Based Application Development. In: Revised Papers from the International

Conference NetObjectDays on Objects, Components, Architectures, Services, and

Applications for a Networked World, p.87-102. 2002.

MEIRELLES, Fernando S. 20ª Pesquisa Anual do Uso de TI. Disponível em

<http://www.eaesp.fgvsp.br/subportais/interna/relacionad/gvciapesq2009.pdf>.

Acesso em: 11 nov. 2009.

OSGi - Wikipedia. Disponível em <http://en.wikipedia.org/wiki/OSGi>. Acessado em

03/10/2009.

OSGi Service Platform Core Specification. Disponível em

<http://www.osgi.org/Download/File?url=/download/r4v41/r4.core.pdf>. Acessado em

03/10/2009.

Referências

Documentos relacionados

Este artigo está dividido em três partes: na primeira parte descrevo de forma sumária sobre a importância do museu como instrumento para construção do conhecimento, destaco

Para esse fim, analisou, além do EVTEA, os Termos de Referência (TR) do EVTEA e do EIA da Ferrogrão, o manual para elaboração de EVTEA da empresa pública Valec –

Local de realização da avaliação: Centro de Aperfeiçoamento dos Profissionais da Educação - EAPE , endereço : SGAS 907 - Brasília/DF. Estamos à disposição

De seguida, vamos adaptar a nossa demonstrac¸ ˜ao da f ´ormula de M ¨untz, partindo de outras transformadas aritm ´eticas diferentes da transformada de M ¨obius, para dedu-

O termo extrusão do núcleo pulposo aguda e não compressiva (Enpanc) é usado aqui, pois descreve as principais características da doença e ajuda a

O valor da reputação dos pseudônimos é igual a 0,8 devido aos fal- sos positivos do mecanismo auxiliar, que acabam por fazer com que a reputação mesmo dos usuários que enviam

A partir das análises realizadas no que tange às articulações entre processo formativo que enfatizou a ressignificação e aplicação, inferimos que a aplicação da SEA replanejada no

Apesar dos esforços para reduzir os níveis de emissão de poluentes ao longo das últimas décadas na região da cidade de Cubatão, as concentrações dos poluentes