Child pages
  • Disparo e Cooperação entre Desktops CSBase
Skip to end of metadata
Go to start of metadata

Desktops CSBase

DOCUMENTO EM CONFECÇÃO

Em fase de testes, o CSBase possui o recurso de disparo e cooperação entre dois desktops (clientes); sejam eles referentes ao mesmo sistema ou não. Por exemplo, um sistema CSBase-X pode, através de seu desktop, disparar um cliente de outro sistema CSBase-Y. Uma vez instanciado o desktop Y, o sistema X pode enviar comandos que controlem o comportamento do desktop Y.

Tal funcionalidade fica disponível se os seguintes requisitos forem cumpridos:

  1. Ambas as instalações (dos sistemas X e Y) estejam conectadas ao OpenBus; ou seja, os seus respectivos serviços de acesso ao OpenBus (OpenBusService) estejam habilitados, ativos e conectados ao mesmo barramento.
  2. O serviço OpenURLService esteja habilitado e ativo, pelo menos, no sistema que pretende disparar o outro desktop CSBase. No caso do nosso exemplo, o sistema X deve habilitar e configurar este serviço corretamente.

Os dois quesitos descritos acima são, evidentemente, server-side. Ou seja, são recursos que o servidor precisa ter ajustado para que tudo funcione. Do outro lado (client-side), é necessária a codificação de componentes no cliente que permitam controlar o disparo e o controle do desktop a ser executado.

No modo mais rudimentar, basta acessar o serviço OpenURLService para obter uma URL e dispará-la. Só isso já permite que o novo desktop seja executado. No entanto, existem componentes já preparados no CSBase que facilitam tal codificação e oferecem métodos de controle previamente determinados; o que reduz consideravelmente o HH de codificação.

O modo mais simples de implementar a parte cliente é pela configuração de uma aplicação já preparada para tal. Ou seja, basta definir no repositório de aplicativos do sistema, uma aplicação cuja implementação é definida pela classe DesktopLauncher.

Para usar o aplicativo básico DesktopLauncher, são necessários os seguintes passos básicos:

  1. Configurar o novo aplicativo no repositório de aplicações do servidor CSBase-X. No nosso exemplo, vamos identificar este aplicativo como ylauncher (este será o identificador da nova aplicação);
  2. Ajustar os seus respectivos atributos para determinar que sistema terá seu desktop lançado. Além disso, alguns recursos básicos podem ser ajustados como: ícones, nomes (baseados em Locale)) etc.

A seguir, segue uma explicação de como efetuar cada um dos passos de configuração e ajuste citados.

Configuração do Servidor

Propriedades do serviço OpenBus

Inicialmente o arquivo OpenBusService.properties deve ser habilitado colocando sua propriedade OpenBusService.enabled ajustada para true. Uma vez que isto esteja feito, é fundamental que o serviço tenha suas propriedades OpenBusService.host e OpenBusService.port ajustadas, respectivamente, para a máquina (hostname ou preferencialmente o seu número IP) e para a porta onde o serviço de acesso do OpenBus está executando.

Cabe ressaltar que tal ajuste deve ser idêntico nos dois sistemas envolvidos (X e Y); de forma a que ambos estejam habilitados e ajustados para o mesmo barramento.

Outras configurações do OpenBusService precisam estar ajustadas, como: OpenBusService.certificate.file, OpenBusService.entity.name, OpenBusService.private.key.file etc. A correta configuração de tais atributos pode ser melhor entendida no texto explicativo do próprio serviço em: Publicação de Serviços no OpenBus

Somente como exemplo, segue a configuração OpenBusService para conexão com um barramento executando na máquina ubu da rede Tecgraf/MSV (ambiente de desenvolvimento).

 # Propriedades do Barramento OpenBus
 OpenBusService.enabled = true

 # Endereço do barramento de desenvolvimento da UBU (10.0.16.56)
 OpenBusService.host = 10.0.16.56
 OpenBusService.port = 3000

 # Certificado digital do Barramento (fornecido pelo administrador do barramento a ser utilizado)
 OpenBusService.certificate.file = security/AccessControlService.crt

 # Nome do servidor no Barramento
 OpenBusService.entity.name = CSBase-X

 # Chave privada deste servidor
 OpenBusService.private.key.file = security/CSBase-X.key


Propriedades do serviço OpenURLService

A configuração deste serviço praticamente define, além de sua habilitação, os endereços e portas dos servidores dos sistemas a que se deseja conectar. Em outras palavras, define-se rótulos (tags) que representam estes sistemas, amarrando-os a endereços de máquinas (hosts ou IPs) e portas. No exemplo a serguir, o arquivo OpenURLService.properties do sistema CSBase-X está configurado para acessar dois sistemas CSBase-Y de produção e desenvolvimento nas máquinas csbase-prod.sistemay.com.br e csbase-dev.sistemay.com.br respectivamente (ambos na porta default 1099).


 # Habilitação do serviço
 OpenURLService.enabled = true


 # Sistemas habilitados (produção e desenvolvimento)
 OpenURLService.predefined.systems.label.1 = Servidor CSBase-Y PROD
 OpenURLService.predefined.systems.host.address.1 = csbase-prod.sistemay.com.br
 OpenURLService.predefined.systems.host.port.1 = 1099

 OpenURLService.predefined.systems.label.2 = Servidor CSBase-Y DEV
 OpenURLService.predefined.systems.host.address.2 = csbase-dev.sistemay.com.br
 OpenURLService.predefined.systems.host.port.2 = 1099


Configuração do Cliente

Mesmo se tratando da configuração do cliente, o ajuste dos aplicativos é feito, pelo administrador do sistema, no serviço de aplicativos (ApplicationService). Os passos básicos, uma vez que já se tenha o sistema instalado, dizem respeito apenas a verificação serviço e seu repositório. Feito isso, basta incluir neste repositório uma entrada relativa ao ylauncher com os atributos corretos. Estes passos são descritos a seguir.

Propriedades do serviço ApplicationService

Apenas para verificação, localizar o diretório que representa o repositório de aplicações no ApplicationService.properties.


 # Ordem de tipos de arquivos de imagens para ícones de um aplicativo
 ApplicationService.image.extension.1 = gif
 ApplicationService.image.extension.2 = png


 # Diretório com repositório de aplicações
 ApplicationService.repository.directory.1 = /csbase-x/applications_repository/


O Repositório de Aplicações

No exemplo acima, temos configurado o sistema CSBase-X para buscar as definições dos aplicativos no diretório /csbase-x/applications_repository/. Isto é o que chamamos de repositório de aplicações. Dentro deste diretório, existem dois subdiretórios applications e categories que representam as aplicações e suas categorizações no sistema.

Criando a Aplicação "YLauncher"

Em /csbase-x/applications_repository/applications, podemos notar que existem vários diretórios. Cada um deles representa o identificador de um aplicativo instalado no sistema. Por exemplo, notepad para o "Bloco de Notas", commandsmonitor para o "Visualizador de Comandos" etc.


[user@host:~] ls /csbase-x/applications_repository/applications
total 100
drwxr-xr-x 3 user group 4096 2010-08-02 10:57 notepad
drwxr-xr-x 3 user group 4096 2010-08-18 12:18 commandsmonitor

...


Para criar uma entrada para o "YLauncher", basta criar um subdiretório com o nome ylauncher, que é o identificador desejado para o novo aplicativo:


[user@host:/csbase-x/applications_repository/applications] mkdir ylauncher
[user@host:/csbase-x/applications_repository/applications] ls
total 100
drwxr-xr-x 3 user group 4096 2010-08-02 10:57 notepad
drwxr-xr-x 3 user group 4096 2010-08-18 12:18 commandsmonitor

...

drwxr-xr-x 3 user group 4096 2010-08-18 12:18 ylauncher

...


Dentro do diretório do aplicativo, é fundamental que existam três arquivos:

  • A imagem (ícone) de 16x16 pixels do aplicativo (nome na sintaxe <id>.16.gif)
  • A imagem (ícone) de 32x32 pixels do aplicativo (nome na sintaxe <id>.32.gif)
  • O arquivo de propriedades do aplicativo (nome na sintaxe <id>.properties)


No nosso exemplo (id da aplicação é ylauncher}, teremos:

[user@host:/csbase-x/applications_repository/applications] ls ylauncher
total 100
drwxr-xr-x 3 user group 4096 2010-08-02 10:57 ylauncher.16.gif
drwxr-xr-x 3 user group 4096 2010-08-02 10:57 ylauncher.32.gif
drwxr-xr-x 3 user group 4096 2010-08-02 10:57 ylauncher.properties


As imagens são definidas conforme o desejo do administrador do sistema (respeitando-se os tamanhos em pixels). O arquivo de propriedades (ylauncher.properties no exemplo) é o que realmente vai definir o comportamento da aplicação.

Configurando a Aplicação "YLauncher"

O arquivo de propriedades da aplicação possui um conjunto fixo de atributos que são pertinentes a todas as aplicações, cujos valores podem ser mexidos conforme o gosto do administrador, como por exemplo: name.pt.BR, name.en.US etc.

ylauncher.name.pt.BR = Lançador de Desktop Y
ylauncher.name.en.US = Y Desktop Launcher


Em outros atributos, comuns a todas as aplicações, sugerimos alguns valores que correspondem a realidade prática de produção; mas que podem ser alterados conforme condições específicas do ambiente. São eles:

  • enabled - indica que a aplicação está habilitada e normalmente assume o valor true.
  • singleton - indica que a aplicação só pode ser instanciada uma única vez. Normalmente, assumimos false para maior flexibilidade.
  • main.frame.visible - indica que a janela principal do aplicativo deve inicialmente ser visível. Normalmente, usamos o valor true para que exista uma janela com dados relevantes do que está ocorrendo.
  • require.project - indica que a aplicação exige que haja um projeto aberto para que ela rode. No caso de disparo de desktops, o valor recomendado é false.

No caso específico do disparo de desktops, pode ser interessante o atributo main.frame.visible assumir o valor false; de modo a não poluir muito o ambiente do usuário com janelas.


Ajuste típico para o exemplo:

ylauncher.enabled = true
ylauncher.require.project = false
ylauncher.singleton = false
ylauncher.main.frame.visible = true


Alguns atributos, por outro lado, devem assumir um valor específico. São eles:

  • class.name - indica a classe de implementação do aplicativo e deve ter o valor csbase.client.applications.desktoplauncher.DesktopLauncher.
  • need.bundle - indica que a aplicação foi implementada usando o mecanismo de internacionalização (bundle) interno conforme o padrão CSBase. Este é o caso do DesktopLauncher

Ajuste típico para o exemplo:

ylauncher.class.name = csbase.client.applications.desktoplauncher.DesktopLauncherEventHandler
ylauncher.need.bundle = true


Abaixo, segue um exemplo completo de configuração.

ylauncher.name.pt.BR = Lançador CSBASE-Y
ylauncher.name.en.US = CSBASE-Y Launcher

ylauncher.class.name = csbase.client.applications.desktoplauncher.DesktopLauncher
ylauncher.enabled = true
ylauncher.require.project = false

ylauncher.shown.at.application.panel = true
ylauncher.shown.at.application.menu = true
ylauncher.singleton = false
ylauncher.main.frame.visible = true

ylauncher.need.bundle = true

ylauncher.system.label = Servidor CSBase-Y PROD
ylauncher.event.handler.class = csbase.client.applications.desktoplauncher.DesktopLauncherEventHandler
ylauncher.initial.application.id = notepad
ylauncher.initial.project.id = $LOGIN::projeto_teste
ylauncher.initial.application.requires.project = true
ylauncher.child.desktop.visible = false

Ajustando a Aplicação "YLauncher"

Observe no exemplo acima que, ao definir o campo ylauncher.system.label, deve existir um tag correspondente no serviço de URLs (OpenURLService). No exemplo, notar que o tag "Servidor CSBase-Y PROD" está presente na definição da aplicação e na configuração do serviço:

  • OpenURLService.predefined.systems.label.1 = Servidor CSBase-Y PROD
  • OpenURLService.predefined.systems.host.address.1 = csbase-prod.sistemay.com.br
  • OpenURLService.predefined.systems.host.port.1 = 1099


Isto ocorre porque os atributos (até agora descritos) definem o comportamento típico de qualquer aplicação CSBase. Porém, em particular, existem alguns campos específicos do DesktopLauncher, que também são descritos no arquivo de propriedades. Tais campos são:

  • system.label - indica a tag, junto ao OpenURLService, no sistema terá seu desktop executado.
  • event.handler.class - indica a classe que implementará o tratador de eventos da aplicação; que é um conceito mais avançado e descrito mais adiante. Normalmente, deve-se usar, uma classe já pronta (pré-definida) do CSBase: csbase.client.applications.desktoplauncher.DesktopLauncherEventHandler.
  • initial.application.id - indica o id de um aplicativo a ser incialmente lançado pelo novo desktop (a ser lançado). Cabe ressaltar que, no caso do nosso exemplo, este id é um identificador do sistema CSBase-Y.
  • initial.project.id - indica, no formato "<login_do_usuário_dono_do_projeto>::<nome_do_projeto>" que o novo desktop deve entrar abrindo um projeto específico. Este é um recurso opcional e pode assumir o valor "null", se desejado.
  • initial.application.requires.project - informa que o aplicativo a ser lançado inicialmente no novo desktop requer o sucesso da abertura de um projeto.
  • child.desktop.visible - indica que o novo desktop deverá iniciar e ficar visível. Se esta chave estiver com o valor false o novo desktop começa oculto.

Se o atributo initial.application.requires.project estiver ajustado para true e houver falha na abertura do projeto (no novo desktop) conforme definido em initial.project.id, o aplicativo definido por initial.application.id não será lançado.


O atributo initial.project.id permite que o trecho que define o login do usuário (dono do projeto) assuma o valor
"$LOGIN". Isto significa que o projeto a ser aberto terá como owner (dono) o usuário corrente. No nosso exemplo, isto significa quem está loggado no desktop-X.

Categorização do YLauncher

No repositório de aplicativos, é possível definir as categorias (agrupamentos) em que a aplicação está inserida. Tal característica é comum a qualquer aplicação CSBase. Logo, fica a critério do administrador do sistema tal definição.
Como exemplo, vamos colocar o ylauncher na categoria "Ferramentas".

No repositório de aplicativos, existe um diretório categories, conforme a ilustração a seguir.

[user@host:/csbase-x/applications_repository] ls
total 8
drwxr-xr-x 28 user group 4096 2010-08-18 12:17 applications
drwxr-xr-x 10 user group 4096 2009-09-23 15:18 categories


Dentro de categories, existem subdiretórios cujos nomes representam o identificador da categoria. Por exemplo,
tools, admin, {{viewers} etc.

[user@host:/csbase-x/applications_repository] ls categories
total 8
drwxr-xr-x 28 user group 4096 2010-08-18 12:17 tools
drwxr-xr-x 10 user group 4096 2009-09-23 15:18 admin
drwxr-xr-x 10 user group 4096 2009-09-23 15:18 viewers


Dentro de cada subdiretório, existem (de forma análoga ao descrito para aplicações) três arquivos que descrevem as imagens da categoria (16x16 e 32x32 pixels) e um arquivo que descreve o agrupamento. No nosso exemplo, temos:

[user@host:/csbase-x/applications_repository] ls categories/tools
total 8
drwxr-xr-x 28 user group 4096 2010-08-18 12:17 tools.16.gif
drwxr-xr-x 10 user group 4096 2009-09-23 15:18 tools.32.gif
drwxr-xr-x 10 user group 4096 2009-09-23 15:18 tools.properties


No arquivo de propriedades, existem chaves (prefixadas pelo id da categoria) que informam o nome da categoria levando em conta a internacionalização e os ids dos aplicativos pertencentes ao grupo. No exemplo abaixo, basta conferir se o id ylauncher está presente.

tools.name.pt.BR = Ferramentas
tools.name.en.US = Tools

tools.application.1 = notepad
tools.application.2 = commandsmonitor
tools.application.3 = ylauncher

Tópicos Avançados

Esta seção tem o objetivo de explicar a forma como desenvolvedores podem, usando a infra-estrutura do CSBase, implementar outras formas de comunicação entre clientes (desktops) de sistemas. Tal tipo de decisão pode ser feita em várias camadas da implementação do cliente (das mais complexas até as mais simples) e, em cada caso, é necessário saber os recursos já existentes.

A forma mais direta, é usando o aplicativo DesktopLauncher na sua forma default; o que já foi descrito acima. No entanto, existem outras formas:

Simples Disparo de Outros Desktops

Se o objetivo for o simples disparo do desktop de um outro sistema, existe uma opção bastante imediata de implementação, que envolve dois passos:

  1. Usar o serviço OpenURLService para montar uma URL de lançamento do novo desktop
  2. Disparar a URL recebida

No passo 1, o serviço OpenURLService oferece métodos que retornam uma URL que, ao executada (passo 2), dispara o novo desktop. O disparo do novo desktop pode ser feito pelo navegador (browser) ou outro sistema como o Java Web Start.
No CSBase, existem classes e métodos que fazem este procedimento. Ou seja, dada uma URL, a classe ExternalResources oferece mecanismos de disparo da URL, abstraindo mecanismos nativos do Java (classe javax.jnlp.BasicService).

Exemplo de código


import csbase.client.externalresources.ExternalResources;

class MyClass {
  private boolean fireURL(final URL url) {
    final ExternalResources extResources = ExternalResources.getInstance();
    if (!extResources.isEnabled()) {
       // Falha, pois o cliente não foi disparado com um JNLP (Java Web Start)
       return false;
    }
    else {
       final boolean ok = extResources.showDocument(url);
       return ok;
    }
  }
}


No trecho descrito acima, assumimos que o método fireURL() recebeu a URL devidamente montada. Tal montagem, conforme descrito anteriormente, é feita com chamadas remotas ao serviço OpenURLService, através de seu método getSystemURL():

  /**
   * Retorna uma URL de um sistema CSBASE qualquer com base em uma 
   * tag pré-configurada no serviço.
   * 
   * @param locale locale
   * @param credential credencial
   * @param systemLabel tag configurada no serviço para escolha do 
   *        servidor/sistema (ver configuração do serviço).
   * @param currentClientId identificador do cliente que chamou a ação.
   * @param newClientId identificador para o novo cliente a ser lançado.
   * @param startVisible indicativo se o novo desktop deve aparecer inicialmente visível.
   * @return a URL.
   * @throws RemoteException em caso de falha RMI.
   */
  public URL getSystemURL(Locale locale, Credential credential,
    String systemLabel, String currentClientId, String newClientId, boolean startVisible)
    throws RemoteException;


A chamada do método acima, monta uma URL que, se disparada, cria um novo desktop. Algumas características muito importantes devem serem observadas:

  • O parâmetro credential garante que o novo desktop seja lançado com a credencial de quem o lança. Ou seja, não será exibida nova uma tela de login. E ambos os clientes estarão conectados a uma mesma sessão no barramento.
  • O parâmetro systemLabel indica, conforme configuração do serviço, que o novo desktop se refere a um determinado sistema, instalado em uma máquina/porta.
  • currentClientId e newClientId representam, respectivamente, identificadores dos componentes (desktops) em execução e a ser lançado. Estes "ids" são importantes para determinar a origem/destino dos eventos trocados na sessão do barramento.

Lembrete: Ao fazer chamadas demoradas ou remotas em um componente cliente, é importante lembrar de usar mecanismos que não travem e Thread da EDT do Java. No CSBase, recomendamos o uso da classe csbase.client.desktop.Task, cuja leitura é recomendada.


Tratando Eventos no Cliente

Uma vez que dois componentes clientes (desktops, tipicamente) estejam executando na mesma sessão do OpenBus, eles podem trocar eventos ou mensagens; o que é feito pelo serviço de sessão do barramento. Existe uma classe CSBase que faz uma abstração desta comunicação: csbase.client.openbus.OpenBusEventHandler.

Esta classe oferece métodos de:

  • Envio de eventos
  • Recebimento de eventos.

Os métodos de recebimentos, em destaque, são os que, se redefinidos por subclasses, implementam a lógica da comunicação. Por default, os tratadores de eventos em OpenBusEventHandler retornam sempre false; ou seja, o evento não é tratado e não faz nada.


 ...

  public boolean receiveEventWithNoValue(String sourceId, 
  String destId, String type) {
    return false;
  }

  public boolean receiveEventWithStringValue(String sourceId, 
  String destId, String type, String stringValue) {
    return false;
  }

  public boolean receiveEventWithBooleanValue(String sourceId, 
  String destId, String type, boolean booleanValue) {
    return false;
  }

 ...


Quando se deseja, de fato, produzir efeitos de colaboração entre componentes, devemos criar uma classe-filha de OpenBusEventHandler de modo a redefinir alguns receptores para implementar o comportamento desejado. Por exemplo, vamos supor que, ao receber uma mensagem de tipo "ESCREVA", desejamos jogar no console a data/hora corrente.

public class EscrevaHandler extends OpenBusEventHandler {
  
  final protected String MY_ID = "MEU_ID";

  final protected String ESCREVA_TYPE = "ESCREVA";

  public boolean receiveEventWithNoValue(String sourceId, 
  String destId, String type) {
    if (destId != null && destId.equals(MY_ID) && 
       type != null && type.equals(ESCREVA_TYPE) {
         final Date now = new Date();
         System.out.println(now.toString());
         return true;
    }
    return false;
  }
}


Por outro lado, poderíamos (além de escrever) mandar um evento de volta para o outro componente. Neste caso, basta chamar os métodos de envio.

public boolean sendEventWithNoValue(String sourceId, 
  String destId, String type);
 
public boolean sendEventWithStringValue(String sourceId, 
  String destId, String type, String stringValue);
 
public boolean sendEventWithBooleanValue(String sourceId, 
  String destId, String type, boolean booleanValue);


No exemplo abaixo, temos um novo tratador que, além de escrever a data, informa de volta o atendimento do pedido.

public class Escreva2Handler extends EscrevaHandler {

  final protected String ESCREVI_TYPE = "ESCREVI";
  
  final public boolean receiveEventWithNoValue(String sourceId, 
  String destId,String type) {
    final boolean treated = super.receiveEventWithStringValue(sourceId, destId, type);
    if (treated) {
      // Observar que o destino da mensagem é a origem do tratador e vice-versa!
      boolean sent = sendEventWithNoValue(destId, sourceId, ESCREVI_TYPE);
      if (sent) {
         System.out.println("Respondi!");
      }
    }
    return treated;
  }
}


É muito importante acompanhar a documentação (Javadoc ou código-fonte) da classe OpenBusEventHandler e sua principais sub-classes no CSBase.

Tratador Padrão de Desktops CSBase

O desktop CSBase, classe csbase.client.desktop.DesktopFrame possui um tratador padronizado responsável por reagir de acordo com tipos de eventos pré-determinados, se ele tiver sido lançado por credencial OpenBus. Ou seja, todo desktop CSBase (se conectado ao barramento) está preparado, por default, para usar um tratador implementado pela classe csbase.client.desktop.DesktopFrameOpenBusEventHandler.

Este tratador está preparado para tratar eventos cujos tipos (strings) são definidos pelos nomes da enumeração csbase.client.openbus.OpenBusStandardEvents, cuja leitura é recomendada. Nesta enumeração pode-se acompanhar o que um desktop pode receber e enviar para um outro componente.

Como exemplo, temos:

public enum OpenBusStandardEvents {

  ...


  /**
   * Pedido de abertura de projeto no desktop 
   * (valor string enviado representando o id do projeto).
   */
  PRJ_OPEN_REQ,

  /**
   * Resposta de abertura de projeto no desktop 
   * (valor string enviado representando o id do projeto).
   */
  PRJ_OPEN_SUCCESS_RSP,

  /**
   * Resposta negativa de abertura de projeto no desktop 
   * (valor string enviado representando o id do projeto).
   */
  PRJ_OPEN_FAILED_RSP,

  ...

}

Tais itens da enumeração representam (através de seus nomes) tipos de mensagens que representam o pedido de abertura de um projeto no desktop e as respostas enviadas de volta (sucesso ou falha). Atualmente, usamos o prefixo "REQ" para sinalizar uma requisição e "RSP" para resposta.

Desta forma, o tratador típico de um desktop faz o seguinte tratamento:

public class DesktopFrameOpenBusEventHandler ...

  ...

  /**
   * {@inheritDoc}
   */
  @Override
  public boolean receiveEventWithStringValue(final String sourceId,
    final String destId, final String type, final String stringValue) {
    if (OpenBusStandardEvents.PRJ_OPEN_REQ.isMyType(type)) {
      boolean ok = abreProjeto(stringValue);
      String responseType;
      if (ok) {
          responseType = OpenBusStandardEvents.PRJ_OPEN_SUCCESS_RSP;
      }
      else {
          responseType = OpenBusStandardEvents.PRJ_OPEN_FAILED_RSP;
      }
      sendEventWithStringValue(MY_ID, sourceId, type, stringValue);
      return true;
    }

    return false;
  }

  ...

}

Os Identificadores do Componente

Nos métodos de envio de recebimento de mensagens, existem campos que indicam o id da origem e do destino. Imediatamente, surge a questão de saber qual é, por exemplo, o identificador do meu desktop. A classe csbase.client.Client, possui métodos capazes de ajudar no processo de identificação; pois sempre que um desktop (cliente) é lançado ele já vem automaticamente ajustado com um identificador. O código abaixo ilustra essa consulta.

    final Client client = Client.getInstance();
    final String myId = client.getClientInstanceId();


Além disso, este mesmo desktop pode ter sido disparado por um outro componente (chamado de componente-pai) que possui também uma identificação. Neste caso, a identificação do pai pode também ser inferida com métodos de csbase.client.Client.

    final Client client = Client.getInstance();
    final String fatherId = client.getFatherClientInstanceId();


Vale ressaltar que as identificações de pai e filho são determinadas no uso do método de criação de URL do OpenURLService, conforme o exemplo abaixo.


final String myClientId = client.getClientInstanceId();
final String newClientId = "MY_NEW_SON";
final OpenURLServiceInterface openURLService = ClientRemoteLocator.openURLService;
final URL url = openURLService.getURL(locale, csCredential, myClientId, newClientId, true);

Implementação de Tratadores de Eventos Específicos no DesktopLauncher

A exibição de vários tipos de tratadores de eventos (que fazem a estendem classe OpenBusEventHandler)) ilustra e explica uma potencialidade interessante do aplicativo DesktopLauncher: a possibilidade do programador codificar seu próprio tratador de eventos e, desta forma, fazer automatizações específicas entre especializações de sistemas CSBASE. Isso é feito quando se define a propriedade event.handler.class descrita anteriormente.

Quando esta propriedade não é definida com seu valor padrão (csbase.client.applications.desktoplauncher.DesktopLauncherEventHandler), o aplicativo automaticamente (por reflexão) tenta criar uma instância dessa classe. Esta criação é feita com o método Class.forName(className) e a posterior busca/chamada de um construtor público de assinatura padronizada: que recebe um objeto do tipo DesktopLauncher como parâmetro, conforme a construção:

      

  final Class<DesktopLauncherEventHandler> superClass = DesktopLauncherEventHandler.class;
  final Class<? extends DesktopLauncherEventHandler> handlerClass = 
     forNameClass.asSubclass(superClass);
 
  ...

  final Constructor<? extends DesktopLauncherEventHandler> constructor = 
     handlerClass.getDeclaredConstructor(DesktopLauncher.class);

Se o objeto for criado com sucesso, ele será usado como o tratador de eventos da aplicação. Caso contrário, um log detalhado é exibido e o tratamento de eventos fica inibido.

FAQ (Respostas às Perguntas mais Freqüentes)

P: Ao depurar o CSBase ou um tratador (com print's, por exemplo), vejo que eu recebo eventos que eu mesmo envio. Há algum erro nisso?
R: Não. Isso é chamado loopback. Sempre que você coloca um evento na sessão do barramento, todos os componentes desta sessão estão aptos a receber a mensagem. Tipicamente, tratamos isso verificando a origem e o destino (sourceId e destId) do evento. Conforme o caso, descartamos o mesmo. A própria classe OpenBusEventHandler possui um método boolean isMyId(String id) capaz de verificar se um id é o do seu próprio cliente.

    final boolean isLoopBack = isMyId(sourceId); 



P: Ao enviar eventos, eu preciso passar necessariamente o meu identificador de remetente (sourceId)?
R: Não. Você pode passar null. Mas alguns tratadores podem não tratar eventos de origem não identificada. Neste caso é bom conferir o comportamento dos tratadores envolvidos, principalmente os já codificados internamente no CSBase (ver método boolean isAnonymousId(String id) de OpenBusEventHandler.

    // Exemplo de código de tratador que dispensa eventos sem origem (sourceId == null).
    boolean isFromUnknown = isAnonymousId(sourceId)
    if (isFromUnknown) return false;



P: Ao enviar eventos, eu preciso passar necessariamente um identificador de destinatário (destId)?
R: Não. Você pode passar null. Mas alguns tratadores podem não tratar eventos que não sejam especificamente enviados para ele. Ao enviar null como destinatário, todos os componentes do barramento que compartilham a sessão ficam aptos a recebê-lo (inclusive por loopback). Neste caso é bom conferir o comportamento dos tratadores envolvidos, principalmente os já codificados internamente no CSBase. Abaixo, segue um trecho de código (método) que pode vir a ser
usado em algum tratador

  final protected boolean isEventFromIdentifiedSourceAndToMe(String sourceId,
    String destId) {
    if (isAnonymousId(sourceId)) {
      return false;
    }
    if (!isMyId(destId)) {
      return false;
    }
    return true;
  }



P: Eu gostaria de simplesmente fazer uma ação (na toolbar do desktop, por exemplo) que simplesmente disparasse um desktop do sistema Xpto. Como fazer isso de modo rápido sem precisar definir uma nova aplicação?
R: No seu método actionPerfomed() da sua ação, você aciona o OpenURLService, como descrito antes e, em seguida dispara a URL. Neste caso, o novo desktop é simplesmente lançado e não há mais nenhuma forma de comunicação com ele. Tipicamente, seria algo do tipo (simplificadamente):

    // Este trecho de código deve vir dentro de uma Task para não prender a EDT...
    final String myClientId = client.getClientInstanceId();
    final String newClientId = "MY_SON_ID";
    final URL url = openURLService.getURL(locale, csCredential, 
         myClientId, newClientId, true);
    final ExternalResources extResources = ExternalResources.getInstance();
    extResources.showDocument(url);


P: É possível criar várias aplicações distintas (chamando vários sistemas diferentes) usando o DesktopLauncher (classe DesktopLauncher)?
R: Sim! Basta criar um identificador diferente (para cada uma das aplicações desejadas) no seu repositório de aplicações. Para cada uma delas, é necessário configurar o tag do sistema (máquina/porta) correspondente a cada um dos sistemas, segundo do atributo system.label.



  • No labels