Avançar para a área de conteúdo

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

Todas as informações enviadas são seguras.

  • Fechar [x]

Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

Todas as informações enviadas são seguras.

  • Fechar [x]

Construindo Aplicativos OSGi com a Especificação Blueprint Container

Jarek Gawor, Advisory Software Engineer, IBM
Author photo
Jarek Gawor é um advisory software engineer da IBM no Research Triangle Park, Carolina do Norte, no Software Group. Ele é um committer do Apache Geronimo e membro do PMC. Ele é Mestre em Ciência da Computação pelo Instituto de Tecnologia de Illinois.

Resumo:  A estrutura Open Service Gateway initiative (OSGi) Alliance está se tornando cada vez mais popular. Ela fornece excelentes mecanismos para desenvolvimento de aplicativos modulares e dinâmicos. As recentes especificações do OSGi Service Platform Release 4 V4.2 introduziram a especificação Blueprint Container. Neste artigo, saiba como o Blueprint Container fornece um modelo de programação simples para a criação de aplicativos dinâmicos no ambiente OSGi sem incluir complexidade ao código Java™ . Vários exemplos ajudam a apresentar o arquivo XML de Blueprint e as definições XML do componente.

Data:  16/Dez/2009 (Publicado em: 16/Dez/2009)
Nível:  Intermediário
Atividade:  1859 visualizações
Comentários:  


Introdução

A estrutura OSGi, que fornece excelentes mecanismos para desenvolvimento de aplicativos modulares e dinâmicos, tem crescido em popularidade. As recentes especificações do OSGi Service Platform Release 4 V4.2 introduziram uma especificação chamada Blueprint Container.

Módulos dinâmicos Spring

Se você está familiarizado com a estrutura Spring, você notará muitas similaridades entre o Spring e a especificação Blueprint Container. A especificação Blueprint se baseia no projeto Spring Dynamic Modules.

A especificação Blueprint Container define uma estrutura de injeção de dependência para o OSGi. Ela é projetada para lidar com a natureza dinâmica do OSGi, na qual os serviços podem ser disponibilizados e indisponibilizados a qualquer momento. A especificação também é projetada para funcionar com objetos Java simples antigos (POJOs) para que os mesmos objetos possam ser usados dentro e fora da estrutura OSGi. Os arquivos XML de Blueprint que definem e descrevem os vários componentes de um aplicativo são fundamentais para o modelo de programação Blueprint. A especificação descreve como os componentes são instanciados e conectados entre si para formar um aplicativo em execução.

A especificação Blueprint Container usa um padrão de extensor por meio do qual um pacote configurável do extensor monitora o estado dos pacotes configuráveis na estrutura e executa ações em nome desses pacotes configuráveis com base em seu estado. O pacote configurável do extensor do Blueprint aguarda a ativação dos pacotes configuráveis e verifica se eles são pacotes configuráveis do Blueprint. Um pacote configurável é considerado um pacote configurável do Blueprint quando contém um ou mais arquivos XML de Blueprint. Esses arquivos XML estão em um local fixo sob o diretório OSGI-INF/blueprint/ ou são especificados explicitamente no cabeçalho do manifesto Bundle-Blueprint .

Depois que o extensor determina que um pacote configurável é um pacote configurável do Blueprint, ele cria um Blueprint Container em nome desse pacote configurável. O Blueprint Container é responsável por:

  • Analisar os arquivos XML de Blueprint
  • Instanciar
  • Conectar os componentes

Durante a inicialização, o Blueprint Container certifica-se de que as referências de serviço obrigatórias sejam satisfeitas, registra todos os serviços no registro de serviço e cria instâncias do componente inicial. O pacote configurável do extensor do Blueprint também destrói o Blueprint Container para um pacote configurável quando o pacote configurável é interrompido.

Este artigo foca o Blueprint XML. Saiba, com vários exemplos, sobre as definições XML do componente e seu uso.


XML de Blueprint

O arquivo XML de Blueprint é identificado por um elemento de nível superior blueprint , como mostrado na Lista 1.


Lista 1. Fragmento do arquivo XML de Blueprint

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns=”http://www.osgi.org/xmlns/blueprint/v1.0.0”>
    ...
</blueprint>

O arquivo XML de Blueprint contém definições de vários gerenciadores de componente. A especificação Blueprint Container define quatro gerenciadores de componente principais: um gerenciador de bean, um gerenciador de serviço e dois gerenciadores de referência de serviço. Cada gerenciador é responsável por criar e gerenciar o ciclo de vida dos componentes que eles criam. Quando solicitados, os gerenciadores fornecem uma instância do componente. Cada gerenciador tem um elemento XML correspondente que descreve as propriedades do gerenciador. Os gerenciadores podem ser gerenciadores de nível superior ou sequenciais dentro de outras definições do gerenciador. Os gerenciadores também compartilham alguns atributos comuns.

id
Define o ID do gerenciador. O atributo id é opcional. Se ele não for especificado, um ID exclusivo será automaticamente gerado e designado a um gerenciador de nível superior. Os gerenciadores sequenciais são considerados anônimos e a eles não é permitida a configuração do atributo id . Os IDs de gerenciador devem ser exclusivos para gerenciadores de nível superior dentro do Blueprint Container. Os IDs são usados para que os gerenciadores possam fazer referência aos outros. Por exemplo, durante a injeção, o gerenciador pedirá aos gerenciadores referenciados para fornecerem um objeto que será injetado no componente que o gerenciador está criando.
ativação
Este atributo opcional define o modo de ativação para o gerenciador. Dois modos de ativação são suportados:
  • eager, em que o gerenciador é ativado durante a inicialização do Blueprint Container.
  • lazy, em que o gerenciador é ativado sob demanda.
Por padrão, o modo de ativação eager é assumido. Porém, o modo de ativação padrão para todos os gerenciadores dentro do arquivo XML de Blueprint pode ser alterado configurando-se o atributo default-activation no elemento blueprint . Um gerenciador é ativado quando for solicitado o fornecimento de sua primeira instância do componente. Um gerenciador é desativado quando o Blueprint Container estiver sendo destruído. Cada gerenciador tem suas próprias etapas de ativação e desativação.
dependsOn
Este atributo opcional especifica uma lista de IDs do gerenciador. Os gerenciadores listados serão ativados primeiro, antes que o gerenciador seja ativado. Um gerenciador pode ter dependências explícitas e implícitas. O atributo dependsOn define as dependências explícitas. As dependências implícitas são definidas pelas referências a outros gerenciadores dentro de uma definição de gerenciador.

Gerenciador de Bean

Um gerenciador de bean cria uma instância de um objeto Java com os argumentos e propriedades fornecidos. Um gerenciador de bean pode criar instâncias de objeto únicas ou múltiplas dependendo das configurações do escopo. Ele também pode gerenciar o ciclo de vida de um objeto e notificá-lo quando todas as propriedades tiverem sido injetadas ou quando ele estiver sendo destruído.

No XML de Blueprint, um elemento bean define um gerenciador de bean. Os argumentos usados para a construção do objeto são especificados pelos elementos argument ; as propriedades injetadas são especificadas pelos subelementos property .

Desambiguidade de assinatura

A especificação Blueprint define um algoritmo com múltiplas etapas para a desambiguidade de assinatura. O algoritmo considera todos os possíveis construtores e a disposição dos parâmetros dentro de cada construtor para localizar a melhor correspondência. O mesmo algoritmo é usado com métodos. A seção 121.9.1 da especificação tem mais detalhes.

Durante a construção do objeto, o Blueprint Container deve primeiro localizar o construtor correto ou um factory method com um conjunto compatível de parâmetros que corresponda aos argumentos especificados no XML. Por padrão, o Blueprint Container usa o número e ordem dos elementos argument no XML para localizar o construtor ou método correto. Se os elementos argument não puderem ser mapeados para os parâmetros na ordem em que estão, o Blueprint Container tentará reordenar os elementos argument e localizar a disposição que melhor se ajuste.

Para ajudar o Blueprint Container a escolher o construtor, método ou disposição de parâmetro correto, atributos adicionais, como index ou typepodem ser especificados no elemento argument . Por exemplo, o atributo type especifica um nome de classe usado para corresponder ao elemento argument para um parâmetro pelo tipo exato.

O elemento property especifica o nome e valor da propriedade para injetar. O nome da propriedade corresponde a um nome de método setter na classe Java. Por exemplo, se o nome da propriedade for foo, o método setter correspondente é setFoo(arg). Os nomes de propriedade e nomes de método setter correspondentes seguem o padrão de design para propriedades conforme definido na especificação JavaBeans.

O valor para os elementos argument e property pode ser especificado usando um atributo value ou ref , ou ele pode ser sequencial. O atributo ref especifica o ID de um gerenciador de nível superior e é usado para obter um objeto do gerenciador referenciado como o valor do argumento ou da propriedade. O valor sequencial pode ser qualquer um dos valores XML descritos na seção "Valores de Objeto".

Construção

Um bean pode ser construído de três maneiras usando:

  • Um construtor de classe
  • Um factory method estático
  • Um factory method de instância

As Listas 2, 3 e 4 demonstram três maneiras de construir objetos Java. Cada lista mostra uma classe Java parcial e o extrato XML de Blueprint correspondente que direciona a criação do objeto.

A Lista 2 mostra um exemplo de criação de construtor simples. Neste exemplo, o atributo class especifica o nome da classe Java a instanciar. O Blueprint Container criará o objeto Account passando 1 como o argumento para o construtor e chamando o método setDescription() para injetar a propriedade de descrição.


Lista 2. Exemplo de construtor

   public class Account {
       public Account(long number) {
          ...
       }
       public void setDescription(String description) {
          ...
       }
       public String getDescription() {
          ...
       }
   }

   <bean id=”accountOne” class=“org.apache.geronimo.osgi.Account”>
       <argument value=”1”/>
       <property name=”description” value=”#1 account”/>
   </bean>
            

A Lista 3 mostra uma construção de factory method estático. Neste exemplo, o atributo class especifica o nome da classe que contém um factory method estático. O nome do factory method estático é especificado pelo atributo factory-method . O Blueprint Container chamará o método estático createAccount() na classe AccountFactory e passará 2 como o argumento para criar o objeto Account . Depois que factory retornar o objeto criado, o contêiner o injetará com a propriedade de descrição.


Lista 3. Exemplo de factory method estático

   public class StaticAccountFactory {
       public static Account createAccount(long number) {
          return new Account(number);
       }
   }

   <bean id=”accountTwo” class=“org.apache.geronimo.osgi.StaticAccountFactory”
         factory-method=“createAccount”>
       <argument value=”2”/>
       <property name=”description” value=”#2 account”/>
   </bean>
            

Com uma construção de factory method de instância, como mostrado na Lista 4, são usados dois gerenciadores. Um gerenciador é um factory e o outro usa o factory para criar um objeto. O atributo factory-ref é usado para especificar o ID de um bean de nível superior ou um gerenciador de referência que age como um factory. O objeto factory fornecido deve ter um factory method como especificado pelo atributo factory-method .

No exemplo, o gerenciador de bean accountFactory é o factory. O Blueprint Container criará primeiro a instância AccountFactory com seus próprios argumentos e propriedades. Neste caso, somente um único argumento é especificado: o nome de factory. O Blueprint Container então chamará o método createAccount() na instância AccountFactory e passará 3 como o argumento para criar o objeto Account . Depois que factory retornar o objeto criado, o contêiner o injetará com a propriedade de descrição.


Lista 4. Exemplo de factory method de instância

   public class AccountFactory {
       public AccountFactory(String factoryName) {
          ...
       }
       public Account createAccount(long number) {
          return new Account(number);
       }
   }

   <bean id=”accountFactory” class=“org.apache.geronimo.osgi.AccountFactory”>
       <argument value=”account factory”/>
   </bean>

   <bean id=”accountThree”
         factory-ref=“accountFactory”
         factory-method=“createAccount”>
       <argument value=”3”/>
       <property name=”description” value=”#3 account”/>
   </bean>
            

Escopo

Dependendo da configuração do escopo, um gerenciador de bean pode criar instâncias de objeto únicas ou múltiplas. A especificação Blueprint Container define dois escopos principais:

singleton
O gerenciador de bean cria uma instância única do bean e retorna a instância sempre que for solicitado ao gerenciador que forneça um objeto.
prototype
O gerenciador de bean cria uma nova instância do bean sempre que for solicitado ao gerenciador que forneça um objeto.

Por padrão, o escopo singleton é assumido para gerenciadores de bean de nível superior. O atributo scope não pode ser configurado como um gerenciador de bean sequencial, portanto, os gerenciadores sequenciais sempre são considerados como tendo escopo prototype .

O atributo scope é usado para especificar as configurações de escopo. A Lista 5 mostra duas definições de bean com diferentes configurações de escopo.


Lista 5. Exemplos de escopo

   <bean id=”prototypeAccount” class=“org.apache.geronimo.osgi.Account”
         scope=”prototype”>
       <argument value=”4”/>
   </bean>

   <bean id=”singletonAccount” class=“org.apache.geronimo.osgi.Account”
         scope=”singleton”>
       <argument value=”5”/>
   </bean>
            

Retornos de chamada de ciclo de vida

Um gerenciador de bean também pode gerenciar o ciclo de vida do objeto criado e notificá-lo quando todas as propriedades tiverem sido injetadas ou quando ele estiver sendo destruído. A especificação Blueprint Container define dois métodos de retorno de chamada:

init-method
Especifica um método a ser chamado depois que todas as propriedades tiverem sido injetadas.
destroy-method
Especifica um método a ser chamado depois que o Blueprint Container estiver destruindo a instância do objeto.

O retorno de chamada destroy-method não é suportado para beans no escopo prototype . É responsabilidade do aplicativo destruir essas instâncias. Os dois métodos de ciclo de vida devem ser públicos, não devem tomar nenhum argumento e não devem retornar nenhum valor.

A Lista 6 mostra um exemplo de uma classe Java com métodos de ciclo de vida e uma entrada bean de XML de Blueprint que especifica os atributos init-method e destroy-method .


Lista 6. Exemplo de retorno de chamada de ciclo de vida

   public class Account {
       public Account(long number) {
          ...
       }
       public void init() {
          ...
       }
       public void destroy() {
          ...
       }
   }

   <bean id=”accountFour” class=“org.apache.geronimo.osgi.Account”
         init-method=”init” destroy-method=”destroy”>
       <argument value=”6”/>
       <property name=”description” value=”#6 account”/>
   </bean>
            


Gerenciadores de referência de serviço

Os gerenciadores de referência de serviço fornecem acesso aos serviços registrados no registro de serviço OSGi. Existem dois gerenciadores de referência de serviço definidos pela especificação Blueprint: referência e lista de referência.

Gerenciador de referência

O gerenciador de referência fornece um objeto que é um proxy para o serviço real registrado no registro de serviço. Um proxy permite que o objeto injetado permaneça o mesmo enquanto o serviço de recuperação possa ir e vir ou ser substituído por outro serviço. Chamadas em um proxy que não tem um serviço de recuperação serão bloqueadas até que um serviço seja disponibilizado ou ocorra um tempo limite.

O gerenciador de referência é definido por um elemento reference . A quantidade de tempo que um proxy aguardará para que um serviço de recuperação seja disponibilizado é especificada usando o atributo timeout . Se o atributo timeout não for especificado, o tempo limite padrão de cinco minutos é assumido. O tempo limite padrão também pode ser alterado para todos os gerenciadores de referência no arquivo XML de Blueprint usando o atributo default-timeout no elemento blueprint . Todos os valores de tempo limite são especificados em milissegundos; um valor de 0 significa tempo limite indefinido.

A Lista 7 mostra um exemplo simples de gerenciador de referência. O proxy de serviço terá um tempo limite de 30 segundos.


Lista 7. Exemplo de gerenciador de referência

   <reference id=”serviceReferenceOne”
              interface=”java.io.Serializable”
              timeout=”30000”/>


Gerenciador de lista de referência

O gerenciador de lista de referência fornece um objeto List que contém os objetos proxy de serviço ou objetos ServiceReference , dependendo da configuração do tipo de membro. O objeto List fornecido é dinâmico, pois ele pode crescer e encolher à medida que serviços correspondentes são incluídos ou removidos do registro de serviço. O objeto List é somente leitura e suporta somente um subconjunto da API List .

Os proxies em um gerenciador de lista de referência são diferentes dos proxies em um gerenciador de referência. Eles têm um serviço de recuperação fixo, não possuem um tempo limite e lançam ServiceUnavailableException imediatamente se o serviço de recuperação for indisponibilizado.

O gerenciador de lista de referência é definido por um elemento reference-list . O tipo dos membros no objeto List fornecido é especificado usando o atributo member-type . O atributo member-type suporta dois valores:

service-object
Injeta uma lista de objetos proxy de serviço, assumidos por padrão.
service-reference
Injeta uma lista de objetos ServiceReference .

A Lista 8 mostra um exemplo simples do gerenciador de lista de referência. Os membros List serão proxies de serviço.


Lista 8. Exemplo de gerenciador de lista de referência

   <reference-list id=”serviceReferenceListOne”
                   interface=”java.io.Serializable”
                   member-type=”service-object”/>

Seleção de serviço e proxies

A referência e os gerenciadores de lista de referência compartilham vários atributos. Três atributos compartilhados são usados para a seleção de serviço: interface, component-name e um filter.

É possível usar o atributo interface para especificar uma classe de interface. A classe de interface é usada para dois propósitos: para seleção de serviço e para proxies de serviço. O atributo interface é opcional, mas, se configurado, ele deve especificar uma classe de interface. Para seleção de serviço, a classe de interface é usada para selecionar serviços do registro de serviço registrado com o nome da interface. Para proxies de serviço, os proxies retornados pelos gerenciadores de referência de serviço devem implementar todos os métodos definidos por esta classe de interface. Se o atributo interface não for especificado, o proxy se comporta como se ele implementasse uma interface sem quaisquer métodos.

Também é possível usar os atributos component-name e filter para a seleção de serviço. O atributo component-name é apenas uma maneira conveniente de incluir uma expressão osgi.blueprint.compname=<component-name> no filtro de seleção. De forma semelhante, o atributo filter especifica a expressão de filtro OSGi não processada a ser incluída no filtro de seleção. Os atributos interface, component-name e filter são combinados para criar uma expressão de filtro OSGi principal usada para a seleção de serviço.

Por exemplo, o filtro de seleção para a referência na Lista 7 é (&(objectClass=java.io.Serializable)), enquanto o filtro de seleção para a referência na Lista 9 é (&(objectClass=java.io.Serializable)(osgi.blueprint.compname=myAccount)(mode=shared)).


Lista 9. Exemplo de seleção de serviço

   <reference id=”serviceReferenceTwo”
              interface=”java.io.Serializable”
              component-name=”myAccount”
              filter=”(mode=shared)”/>
            

Disponibilidade

Um gerenciador de referência de serviço pode precisar que pelo menos um serviço que corresponda aos seus critérios de seleção exista antes que a inicialização do Blueprint Container possa continuar. Esse requisito é controlado com o atributo availability . O atributo availability pode ter dois valores:

optional
Serviços que correspondam aos critérios de seleção podem ou não existir.
mandatory
Pelo menos um serviço que corresponda aos critérios de seleção deve existir.

Por padrão, a disponibilidade mandatory é assumida. A configuração de disponibilidade padrão também pode ser alterada para todos os gerenciadores de referência de serviço no arquivo XML de Blueprint usando um atributo default-availability no elemento blueprint .

Um gerenciador de referência de serviço com disponibilidade mandatory que tenha um serviço correspondente é considerado satisfeito. Um gerenciador de referência de serviço com disponibilidade optional sempre é considerado satisfeito mesmo se ele não tiver nenhum serviço correspondente. A inicialização de Blueprint Container será atrasada até que todos os gerenciadores de referência de serviço obrigatórios sejam satisfeitos.

É importante entender que a disponibilidade mandatory somente é considerada durante a inicialização do Blueprint Container. Após a inicialização, a referência de serviço obrigatória pode se tornar insatisfeita à medida que os serviços entrem e saiam em qualquer ponto.

A Lista 10 mostra um exemplo de um gerenciador de referência com disponibilidade mandatory .


Lista 10. Exemplo de disponibilidade

   <reference id=”serviceReferenceThree”
              interface=”java.io.Serializable”
              timeout=”30000”
              availability=”mandatory”/>

Listener de referência

Ambos os gerenciadores de referência de serviço podem ter zero ou mais listeners de referência. Listeners de referência são objetos em que métodos de retorno de chamada são invocados quando o serviço é selecionado pelo gerenciador de referência de serviço ou quando o serviço não é mais usado pelo gerenciador de referência de serviço. Um listener de referência é especificado usando o elemento reference-listener . Os atributos bind-method e unbind-method especificam os métodos de retorno de chamada. O objeto que fornece os métodos de retorno de chamada pode ser sequenciado dentro do elemento reference-listener ou especificado como uma referência a um gerenciador de nível superior.

Ambos os métodos de retorno de chamada de conexão e desconexão podem ter qualquer uma das seguintes assinaturas. (anyMethod representa um nome de método arbitrário.)

void anyMethod(ServiceReference)
O argumento é um objeto ServiceReference do serviço que está sendo conectado ou desconectado.
void anyMethod(? super T)
O argumento é o proxy do objeto de serviço que está sendo conectado ou desconectado. O tipo T deve ser designável a partir do objeto de serviço.
void anyMethod(? super T, Map)
O primeiro argumento é o proxy do objeto de serviço que está sendo conectado ou desconectado. O tipo T deve ser designável a partir do objeto de serviço.O segundo argumento fornece as propriedades de serviço associadas ao serviço.

Se um listener de referência tiver múltiplos métodos sobrecarregados para um retorno de chamada, todos os métodos com uma assinatura correspondente são invocados.

Para um gerenciador de lista de referência, os retornos de chamada do listener são invocados sempre que um serviço correspondente for incluído ou removido do registro de serviço. Porém, para um gerenciador de referência, o retorno de chamada de conexão não será invocado quando o gerenciador já estiver conectado a um serviço e um serviço correspondente com classificação inferior for incluído no registro do serviço. De forma semelhante, o retorno de chamada de desconexão não será chamado quando o serviço ao qual o gerenciador está conectado partir e ele puder ser imediatamente substituído por outro serviço correspondente.

É importante entender que ao usar um gerenciador de referência e interagir com serviços stateful, você deve usar listeners de referência para controlar os serviços de recuperação do proxy para gerenciar o estado do serviço apropriadamente.

A Lista 11 mostra um exemplo de listener de registro simples. A classe ReferenceListener tem dois métodos de retorno de chamada de conexão e um método de retorno de chamada de desconexão, que serão chamados à medida que os serviços forem conectados e desconectados do gerenciador de lista de referência de serviço.


Lista 11. Exemplo de listener de referência

   public class ReferenceListener {
       public void bind(ServiceReference reference) {
           ...
       }
       public void bind(Serializable service) {
           ...
       }
       public void unbind(ServiceReference reference) {
           ...
       }
   }

   <reference-list id=”serviceReferenceListTwo” interface=”java.io.Serializable”
              availability=”optional”>
      <reference-listener
              bind-method=”bind” unbind-method=”unbind”>
          <bean class=“org.apache.geronimo.osgi.ReferenceListener”/>
      </reference-listener>
   </reference-list>


Gerenciador de serviço

Um gerenciador de serviço registra um serviço no registro de serviço OSGi. O gerenciador de serviço registra e cancela o registro do serviço se todos os gerenciadores de referência de serviço obrigatória em suas dependências forem satisfeitos. Como as referências de serviço obrigatórias podem se torna insatisfeitas em qualquer ponto, um gerenciador de serviço retorna um objeto proxy ServiceRegistration que delega as chamadas para o objeto ServiceRegistration real.

Durante a inicialização, um Blueprint Container registra serviços baseados em ServiceFactory para cada gerenciador de serviço no Blueprint Container em vez dos objetos de serviço reais. Esses serviços permitem que o Blueprint Container atrase a criação do objeto à medida que eles interceptam os pedidos de serviço e instanciam o objeto do serviço real somente quando necessário. O objeto do serviço real é fornecido por outro gerenciador, geralmente um gerenciador de bean. O objeto do serviço real pode implementar a interface ServiceFactory do OSGi.

No XML de Blueprint, um elemento service define um gerenciador de serviço. O gerenciador que fornece o objeto de serviço pode ser referenciado usando o atributo ref ou ser sequenciado dentro do elemento service . A Lista 12 mostra dois serviços: um com um gerenciador referenciado e um com um gerenciador sequenciado.


Lista 12. Exemplos de gerenciador de serviço

   <service id=”serviceOne” ref=”account” ... />

   <service id=”serviceTwo” … >
      <bean class=“org.apache.geronimo.osgi.Account”>
          <argument value=”123”/>
      </bean>
   </service>
            

Interfaces de serviço

Cada serviço deve ser registrado sob um ou mais nomes de interface. A lista de nomes da interface para o serviço pode ser especificada explicitamente ou determinada automaticamente a partir do objeto de serviço com base na configuração de exportação automática. Os nomes da interface podem ser configurados explicitamente usando:

  • O atributo interface , que somente pode especificar um único nome de interface.
  • O subelemento interfaces , que permite que qualquer número de interface seja configurado.

A configuração de exportação automática é especificada pelo atributo auto-export e suporta as quatro opções abaixo.

disabled
O valor-padrão se o atributo auto-export não for especificado. A lista de interfaces deve ser especificada usando o atributo interface ou subelementos interfaces .
interfaces
Registre o serviço usando todas as interfaces públicas implementadas pela classe de serviço e quaisquer de suas super classes.
class-hierarchy
Registre o serviço usando a classe de serviço e quaisquer de suas super classes públicas.
all-classes
Combina as opções interfaces e class-hierarchy .

A Lista 13 mostra serviços com três maneiras de especificar as interfaces de serviço. Neste exemplo, os serviços serviceOne e serviceTwo são registrados como uma única classe de interface Serializable , enquanto o serviço serviceThree é registrado com as classes MyAccount, Account e Serializable .


Lista 13. Exemplos de interface de serviço

   public class MyAccount extends Account implements java.io.Serializable {
       ...
   }

   <bean id=”myAccount” class=”org.apache.geronimo.osgi.MyAccount”>
       <argument value=”7”/>
       <property name=”description” value=”MyAccount”/>
   </bean>

   <service id=”serviceOne” ref=”myAccount” interface=”java.io.Serializable”/>

   <service id=”serviceTwo” ref=”myAccount”>
      <interfaces>
          <value>java.io.Serializable</value>
      </interfaces>
   </service>

   <service id=”serviceThree” ref=”myAccount” autoExport=”all-classes”/>
            

Propriedades de serviço

Um serviço também pode ser registrado com um conjunto de propriedades que podem ser especificadas usando o subelemento service-properties . O elemento service-properties contém múltiplos subelementos entry que representam as propriedades individuais. A chave da propriedade é especificada usando um atributo key , mas o valor da propriedade pode ser especificado como um atributo value ou sequenciado dentro do elemento. Os valores da propriedade de serviço podem ser de tipos diferentes, mas somente primitivas, classes do wrapper primitivas, coleções ou arrays de tipos primitivos são permitidos.

A Lista 14 mostra um exemplo de um registro de serviço com duas propriedades de serviço. A propriedade de serviço active tem um valor de tipo java.lang.Boolean . A propriedade mode é do tipo String .


Lista 14. Exemplos de propriedades de serviço

   <service id=”serviceFour” ref=”myAccount” autoExport=”all-classes”>
      <service-properties>
          <entry key=”mode” value=”shared”/>
          <entry key=”active”>
              <value type=”java.lang.Boolean”>true</value>
          </entry>
      </service-properties>
   </service>
            

Uma propriedade osgi.blueprint.compname é automaticamente incluída nas propriedades de serviço se o gerenciador que fornece o objeto de serviço para o serviço for um gerenciador de nível superior. O valor da propriedade osgi.blueprint.compname é o ID do gerenciador de nível superior que fornece a instância de serviço. Por exemplo, dado o exemplo de serviço na Lista 14, o valor da propriedade osgi.blueprint.compname seria configurado para myAccount.

Classificação de serviço

É possível usar o atributo ranking para expor o serviço com uma classificação específica. Se o atributo de classificação não for especificado, o serviço será registrado sem uma classificação. Em casos assim, a estrutura OSGi assume 0 como a classificação padrão para o serviço.

Um exemplo de registro de serviço com uma classificação é mostrado abaixo.


Lista 15. Exemplo de classificação de serviço

   <service id=”serviceFive” ref=”myAccount” auto-export=”all-classes” ranking=”3”/>
            

Listener de registro

Um gerenciador de serviço pode ter zero ou mais listeners de registro, que são objetos cujos métodos de retorno de chamada são invocados logo após o registro do serviço ou logo antes do cancelamento do registro do serviço. Um listener de registro é especificado usando o subelemento registration-listener . Os atributos registration-method e unregistration-method especificam os métodos de retorno de chamada. O objeto que fornece os métodos de retorno de chamada pode ser sequenciado dentro do elemento registration-listener ou especificado como uma referência a um gerenciador de nível superior.

A assinatura dos métodos de retorno de chamada de registro e cancelamento de registro depende de se o objeto de serviço implementa a interface ServiceFactory . Se o serviço implementar a interface ServiceFactory , ambos os métodos devem ter uma assinatura void anyMethod(ServiceFactory, Map) , em que anyMethod representa um nome de método arbitrário.

Se o serviço não implementar a interface ServiceFactory , ambos os métodos de retorno de chamada devem corresponder à assinatura anyMethod(? super T, Map) de anulação, em que o tipo T é designável a partir do tipo de objeto de serviço. O primeiro argumento para o método de retorno de chamada é uma instância do objeto de serviço e o segundo argumento são as propriedades de registro. Se um listener de registro tiver múltiplos métodos sobrecarregados para um retorno de chamada, então todos os métodos com uma assinatura correspondente serão invocados.

A Lista 16 mostra um exemplo de listener de registro simples.


Lista 16. Exemplo de listener de registro

   public class RegistrationListener {
       public void register(Account account, Map properties) {
           ...
       }
       public void unregister(Account account, Map properties) {
           ...
       }
   }

   <service id=”serviceSix” ref=”myAccount” auto-export=”all-classes”>
      <registration-listener
              registration-method=”register” unregistration-method=”unregister”>
          <bean class=“org.apache.geronimo.osgi.RegistrationListener”/>
      </registration-listener>
   </service>
            


Gerenciadores de ambiente

A especificação Blueprint Container também define um número de gerenciadores de ambiente especiais que possuem IDs configurados e fornecem acesso a componentes ambientais. Eles não possuem definição XML e não podem ser substituídos, já que seus IDs são reservados e não podem ser usados com outros gerenciadores. Os objetos fornecidos por gerenciadores de ambiente somente podem ser injetados em outros gerenciadores usando uma referência. A especificação Blueprint Container define quatro gerenciadores de ambiente:

blueprintBundle
Fornece o objeto Bundle do pacote configurável.
blueprintBundleContext
Fornece o objeto BundleContext do pacote configurável.
blueprintContainer
Fornece o objeto BlueprintContainer para o pacote configurável.
blueprintConverter
Fornece o objeto Converter para o pacote configurável que fornece acesso ao recurso de conversão do tipo Blueprint Container. Conversão de tipo tem mais informações.

A Lista 17 mostra um exemplo simples no qual o objeto Bundle fornecido pelo gerenciador de ambiente blueprintBundle é injetado no bean accountManagerOne .


Lista 17. Exemplo de gerenciador de ambiente

   public class AccountManager {
       public void setManagerBundle(Bundle bundle) {
           ...
       }
   }

   <bean id=”accountManagerOne” class=”org.apache.geronimo.osgi.AccountManager”>
      <property name=”managerBundle” ref=”blueprintBundle”/>
   </bean>
            


Valores de objeto

A especificação Blueprint Container define muitos elementos XML que descrevem diferentes tipos de valores de objeto. Esses elementos de valor XML são usados dentro das definições do gerenciador. Por exemplo, eles podem ser usados em um gerenciador de bean para especificar valores de argumento ou de propriedade ou em um gerenciador de serviço para especificar os valores das propriedades de serviço. Os elementos de valor XML são convertidos nos objetos de valor reais e injetados nos componentes do gerenciador.

O elemento ref define uma referência para um gerenciador de nível superior. O atributo component-id especifica um ID de um gerenciador de nível superior. O valor injetado será o objeto retornado pelo gerenciador referenciado.

A Lista 18 mostra um exemplo do elemento de valor ref . A instância bean accountOne é injetada na propriedade managedAccount do bean accountManagerTwo .


Lista 18. Exemplo de valor de referência

   public class AccountManager {
       ...
       public void setManagedAccount(Account account) {
           ...
       }
   }

   <bean id=”accountOne” class=“org.apache.geronimo.osgi.Account”>
       <argument value=”1”/>
       <property name="description" value="#1 account"/>
   </bean>

   <bean id=”accountManagerTwo” class=“org.apache.geronimo.osgi.AccountManager”>
       <property name=”managedAccount”>
           <ref component-id=”accountOne”/>
       </property>
   </bean>
            

O elemento idref define um ID de um gerenciador de nível superior. O valor injetado é o ID de componente conforme especificado pelo atributo component-id . O elemento idref é usado para garantir que o gerenciador do ID especificado realmente existe antes da ativação do gerenciador.

O elemento value representa um objeto a ser criado a partir do conteúdo da cadeia de caracteres do elemento. É possível usar o atributo opcional type para especificar um tipo no qual o conteúdo da cadeia de caracteres deve ser convertido. Se o atributo type não for especificado, o conteúdo da cadeia de caracteres será convertido no tipo no qual está sendo injetado.

O elemento null representa o nulo do Java.

Os elementos list, set e array são coletas e representam um objeto java.util.List , objeto java.util.Set e array Object[] , respectivamente. Os subelementos dessas coletas podem ser qualquer um dos elementos de valor XML descritos nesta seção. O atributo opcional value-type pode ser configurado nesses elementos para especificar um tipo padrão para subelementos da coleta.

O exemplo na Lista 19 mostra como os elementos de valor XML podem ser combinados para criar uma lista. A lista criada conterá os seguintes quatro itens:

  • Uma String "123"
  • Um objeto java.math.BigInteger com valor 456
  • Um nulo
  • Um objeto java.util.Set com dois valores do tipo java.lang.Integer

Lista 19. Exemplo de valor de lista complexa

   <list>
       <value>123</value>
       <value type=”java.math.BigInteger”>456</value>
       <null/>
       <set value-type=”java.lang.Integer”>
           <value>1</value>
           <value>2</value>
       </set>
   </list>
            

O elemento props representa um objeto java.util.Properties no qual as chaves e valores são do tipo String . Os subelementos prop representam as propriedades individuais. A chave da propriedade é especificada usando um atributo key , mas o valor da propriedade pode ser especificado como um atributo value ou como um conteúdo do elemento.

A Lista 20 mostra um exemplo do elemento de valor props .


Lista 20. Exemplo de valor de propriedades

    <props>
        <prop key=”yes”>good</prop>
        <prop key=”no” value=”bad”/>
    </props>
            

O elemento map representa um objeto java.util.Map no qual as chaves e os valores podem ser objetos arbitrários. Os subelementos entry representam as propriedades individuais. A chave pode ser especificada como um atributo key , atributo key-ref , ou sequenciada dentro de um subelemento key . O valor pode ser especificado como um atributo value , atributovalue-ref , ou ser sequenciado. O valor sequenciado pode ser especificado como qualquer um dos elementos de valor XML descritos nesta seção. Porém, a chave sequenciada pode ser especificada como qualquer um dos elementos de valor XML, exceto o elemento null . Chaves nulas não são permitidas nos elementos map na Especificação Blueprint. Os atributos key-ref e value-ref especificam um ID de um gerenciador de nível superior e são usados para obter um objeto a partir do gerenciador especificado como a chave ou o valor de propriedade. O elemento map pode especificar os atributos key-type e value-type para definir um tipo padrão para chaves e valores.

A Lista 21 mostra um exemplo do elemento de valor map . Ela também mostra como as entradas de um objeto map podem ser construídas de várias maneiras. O objeto map criado conterá as seguintes entradas:

  • Uma chave de String myKey1 que é mapeada para String myValue.
  • Uma chave que é um objeto retornado pelo gerenciador de bean account é mapeada para String myValue.
  • Uma chave que é um objeto java.lang.Integer com valor 123 é mapeada para String myValue.
  • Uma chave de String myKey2 é mapeada para um valor que é um objeto retornado pelo gerenciador de bean account .
  • Uma chave de String myKey3 é mapeada para um valor que é um objeto java.lang.Long com valor 345.
  • Uma chave que é um objeto java.net.URI com valor urn:ibm é mapeada para um valor que é um objeto java.net.URL com valor http://ibm.com.

Lista 21. Exemplo de valor de map

   <map>
       <entry key=”myKey1” value=”myValue”/>

       <entry key-ref=”account” value=”myValue”/>
       <entry value=”myValue”>
           <key>
               <value type=”java.lang.Integer”>123</value>
           <key/>
       </entry>

       <entry key=”myKey2” value-ref=”account”>
       <entry key=”myKey3”>
           <value type=”java.lang.Long”>345</value>
       </entry>

       <entry>
           <key>
               <value type=”java.net.URI”>urn:ibm</value>
           <key/>
           <value type=”java.net.URL”>http://ibm.com</value>
       </entry>
   </map>
            

Cada gerenciador também pode ser sequenciado como um valor. A Lista 22 mostra um exemplo de gerenciador bean sequenciado.


Lista 22. Exemplo de valor de gerenciador sequenciado

   <bean id=”accountManagerThree” class=“org.apache.geronimo.osgi.AccountManager”>
       <property name=”managedAccount”>
           <bean class=“org.apache.geronimo.osgi.Account”>
               <argument value=”10”/>
               <property name="description" value="Inlined Account"/>
           </bean>
       </property>
   </bean>
            

Conversão de tipo

Durante a injeção, o Blueprint Container converte os elementos de valor XML em objetos reais. Ele converte os elementos com base no tipo de propriedade injetada. Por exemplo, na Lista 2, o Blueprint Container converte o valor da Cadeia de Caracteres 123 em um valor long . O Blueprint Container fornece diversas conversões integradas, como a conversão de:

  • Valores de cadeia de caracteres em todos os tipos primitivos, tipos de wrapper ou quaisquer tipos que tenham um construtor público que tome um valor de Cadeia de Caracteres.
  • Elementos array em objetos de coleta (com tipos de membros compatíveis).
  • Elementos list ou set em objetos de array (com tipos de membros compatíveis).

O Blueprint Container também suporta genéricos. Se as informações sobre os genéricos estiverem disponíveis, o Blueprint Container usará essas informações para executar as conversões. Por exemplo, na Lista 23, o elemento list será convertido em uma lista de objetos java.util.Long .


Lista 23. Exemplo de conversão de genéricos

   public class AccountManager {
       ...
       public void setAccountNumbers(List<Long> accounts) {
          ...
       }
   }

   <bean id=”accountManagerFour” class=“org.apache.geronimo.osgi.AccountManager”>
       <property name=”accountNumbers”>
           <list>
               <value>123</value>
               <value>456</value>
               <value>789</value>
           </list>
       </property>
   </bean>
            

Além das conversões integradas, um pacote configurável Blueprint pode fornecer seus próprios conversores. Os conversores customizados são gerenciadores de bean que fornecem um objeto que implementa a interface Converter do Blueprint. Os conversores customizados são especificados dentro do elemento type-converters sob o elemento blueprint . Os conversores de tipo são inicializados primeiro durante a inicialização do Blueprint Container para que outros gerenciadores possam aproveitar os conversores customizados. A especificação do Blueprint Container tem mais informações sobre a gravação de conversores customizados.


Experimentando o Blueprint

Para experimentar aplicativos Blueprint, são necessárias duas coisas: uma plataforma OSGi e a implementação do Blueprint Container. Neste artigo, usaremos o Equinox como a plataforma OSGi, mas outras — como a Apache Felix — também funcionariam bem. Para o Blueprint Container, usaremos uma implementação a partir do projeto da incubadora do Apache Aries. A implementação do Blueprint em Aries foi originalmente desenvolvida no projeto Apache Geronimo, mas foi movida para o Aries, no qual está sendo atualmente desenvolvida.

A amostra anexada fornece um bom ponto de início para experimentar o Blueprint. Ela contém dois módulos: blueprint-sample e blueprint-assembly. O módulo blueprint-sample é um pacote configurável Blueprint de amostra. Ele contém muitas das classes Java e definições XML de Blueprint mostradas neste artigo. O módulo blueprint-assembly compacta a estrutura Equinox, a implementação Apache Aries Blueprint e o pacote configurável de amostra juntos em um contêiner fácil de usar.

Construindo a amostra

Faça o download e descompacte a origem da amostra anexada no diretório de sua preferência. Use o Apache Maven para construir a origem da amostra. Execute os comandos na Lista 24 para construir a amostra.


Lista 24. Construindo a amostra

cd sample
mvn install

O Maven automaticamente construirá ambos os módulos na amostra. Depois que a amostra inteira for construída com êxito, o diretório target do módulo blueprint-assembly conterá diversos arquivos JAR. Ele conterá a implementação do Apache Aries Blueprint, o pacote configurável da amostra e alguns outros JARs que fornecem recursos de criação de log para a estrutura OSGi. Ele também conterá o arquivo osgi-3.5.0.v20090520.jar, que fornece a estrutura Equinox. Depois de iniciada, a estrutura Equinox automaticamente instalará e iniciará todos os outros JARs no diretório de destino. Para iniciar a estrutura Equinox, execute os comandos da Lista 25.


Lista 25. Iniciando o Equinox

cd blueprint-assembly/target
java -jar osgi-3.5.0.v20090520.jar -console

O console do Equinox aparecerá após a inicialização bem-sucedida. Use o comando ss para exibir os pacotes configuráveis instalados; a Figura 1 mostra a saída do comando ss .


Figura 1. Saída dos pacotes configuráveis instalados


Executando o pacote configurável de amostra

O pacote configurável de amostra será automaticamente instalado na estrutura Equinox, mas não será iniciado. Para iniciar o pacote configurável de amostra, execute o comando start 5 no console do Equinox; o número 5 é o ID do pacote configurável de amostra org.apache.aries.sample_1.0.0.SNAPSHOT . Depois que o pacote configurável for iniciado com êxito, você deve ver a seguinte saída no console, com mostrado na Figura 2.


Figura 2. Saída do pacote configurável de amostra



Resumo

A especificação Blueprint Container, introduzida na especificação OSGi mais recente, fornece um modelo de programação simples e fácil para a criação de aplicativos dinâmicos no ambiente OSGi sem incluir complexidade no código Java. Com a implementação Aries Blueprint Container, é possível iniciar a construção de aplicativos baseados em Blueprint hoje mesmo.



Download

DescriçãoNomeTamanhoMétodo de download
Sample sourceos-osgiblueprint-sample.zip11KBHTTP

Informações sobre métodos de download


Recursos

Aprender

  • Confira o tutorial Bundles for beginners de OSGi do JavaWorld. Saiba como criar, executar e gerenciar pacotes configuráveis em um contêiner OSGi.

  • Leia mais sobre injeção de dependência.

  • Saiba mais sobre o OSGi Alliance e obtenha as notícias, eventos, fóruns e especificações mais recentes e mais.

  • Apache Geronimo está produzindo uma estrutura de tempo de execução de servidor que reúne alternativas de software livre para criar tempos de execução que satisfaçam as necessidades de desenvolvedores e administradores de sistema.

  • Saiba tudo sobre o Apache Felix.

  • Obtenha uma visão geral do Apache Aries.

  • Os nomes de propriedade e nomes de método setter correspondentes seguem o padrão de design para propriedades conforme definido na especificação JavaBeans .

  • Saiba como os Módulos Dinâmicos Spring facilitam a construção de aplicativos Spring que são executados em uma estrutura OSGi.

  • Para ouvir entrevistas e discussões interessantes para desenvolvedores de software, confira os podcasts do developerWorks.

  • Mantenha-se atualizado com os eventos e webcasts técnicos do developerWorks.

  • Siga o developerWorks no Twitter.

  • Confira as conferências, trade shows, webcasts e outros Eventos futuros no mundo todo que são de interesse dos desenvolvedores de software livre da IBM.

  • Visite a zona de software livre do developerWorks para obter informações extensivas sobre instruções, ferramentas e atualizações de projeto para ajudá-lo no desenvolvimento de tecnologias de software livre e em seu uso com produtos da IBM, assim como nossos mais populares artigos e tutoriais.

  • Assista e aprenda sobre a IBM e tecnologias de software livre e funções de produto com as demos gratuitas do developerWorks On demand.

Obter produtos e tecnologias

Discutir

Sobre o autor

Author photo

Jarek Gawor é um advisory software engineer da IBM no Research Triangle Park, Carolina do Norte, no Software Group. Ele é um committer do Apache Geronimo e membro do PMC. Ele é Mestre em Ciência da Computação pelo Instituto de Tecnologia de Illinois.

Ajuda para Relatar Abuso

Relatar abuso

Obrigado. Esta entrada foi sinalizada para atenção do moderador.


Ajuda para Relatar Abuso

Relatar abuso

Falha no envio do Relatório de abuso. Tente novamente mais tarde.


developerWorks: Registre-se


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

Selecione seu nome de exibição

Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

(Deve possuir de 3 a 31 caracteres.)


Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Classificar este artigo

Comentários

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Software livre
ArticleID=453923
ArticleTitle=Construindo Aplicativos OSGi com a Especificação Blueprint Container
publish-date=12162009
author1-email=jgawor@us.ibm.com
author1-email-cc=

Conheça a IBM da sua cidade

Virtual Branch Office Brasil

A IBM está mais perto do que você imagina!


Tags

Help
Use o campo de pesquisa para encontrar todos os tipos de conteúdo no My developerWorks com essa tag.

Use a barra de rolagem para ver mais ou menos tags.

Tags populares mostra as principais tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Minhas tags mostra suas tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Use o campo de pesquisa para localizar todos os tipos de conteúdo no Meu developerWorks com essa tag. Tags populares mostra as tags principais para essa zona de conteúdo particular (por exemplo, tecnologia Java, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere). Minhas tags mostra as suas tags para essa zona de conteúdo em particular (por exemplo, tecnologia Java, Linux, WebSphere).