Nível: Intermediário Van Staub, Staff Software Engineer, IBM Raj Balasubramanian, Consulting IT Architect, IBM
01/Ago/2009 Aprenda como criar aplicativos da Web RESTful IBM Lotus Domino usando Project Zero para
fornecer um aplicativo Web 2.0 responsivo. Este artigo explora as diversas opções que os
desenvolvedores têm para criar aplicativos da Web RESTful Lotus Domino e mostra como é possível
fornecer tais aplicativos com a ajuda do Project Zero.
Criar aplicativos IBM Lotus Domino usando Project Zero permite que desenvolvedores criem aplicativos interessantes, responsivos e
dinâmicos no estilo Web 2.0 com facilidade. Em vez de criar aplicativos desde o início,
desenvolvedores podem usar APIs ricas em recursos do Project Zero para desenvolver e implementar
rapidamente os aplicativos Lotus Domino com aparência e sensação de Web 2.0. Este artigo
percorre o padrão básico que um desenvolvedor do Lotus Domino pode usar para criar aplicativos
da Web ativados para REST. Ao fazer isso, também indicamos os recursos do Projeto Zero que
permitem que desenvolvedores se concentrem na interação do Lotus Domino em vez de no gasto
adicional associado à programação para a Web.
REST
Representational State Transfer (REST) é um estilo de arquitetura de software para construir
um sistema distribuído, que a própria Web incorpora. O recente interesse em torno de Web 2.0 e a
complexidade de padrões de serviços da Web existentes permitiram o retorno de REST como um
estilo viável para construir serviços da Web. A abordagem REST de projetar sistemas distribuídos
permite usar a maior parte do que HTTP oferece na construção do aplicativo.
REST pode ser destilado em alguns princípios chave:
- Recurso. Qualquer coisa importante é um recurso e deve receber esse status. A ideia
chave de um recurso é o de endereçabilidade, usando URL/URI.
- Operações e métodos uniformes. HTTP introduz quatro métodos primários e os serviços
baseados em REST usam esses métodos para expor a funcionalidade dos serviços. Por exemplo, uma
operação para visualizar um recurso é implementada usando o método GET da interface HTTP.
Detalhes dos métodos são cobertos posteriormente neste artigo.
- Cabeçalhos. Os cabeçalhos HTTP transportam meta informações, como informações sobre
autenticação, código de resposta e mensagens de erro do servidor, o tipo de conteúdo do recurso
que está sendo servidor pelo servidor e mais. Alguns dos cabeçalhos chave usados para abordar
requisitos não funcionais são cobertos posteriormente também. À medida que o número aumenta em
qualquer projeto de desenvolvimento de aplicativos, o número de artefatos produzidos e o
gerenciamento dos sistemas que suportam o aplicativo também aumentam. Em uma implementação
típica de Arquitetura Orientada a Serviços (SOA), um número de camadas é apresentado para
facilitar a separação de interesses e para ajudar no acoplamento fraco.
- Representação flexível. HTTP pode fornecer diversos usos para o recurso baseado no
que o cliente ou o consumidor pode usar. Diversos tipos MIME definidos podem ser usados para
fornecer um recurso no formato XML, JSON ou HTML. Melhor ainda, o cliente pode especificar
quais formatos pode aceitar.
 |
Sobre o Aplicativo Lotus Domino
Estendemos a demo Employees do Project Zero para demonstrar interfaces semelhantes a REST
usando um aplicativo Lotus Domino Employees, baseado no modelo IBM Lotus Domino Directory. As
versões 7.0x e acima do Lotus Domino são suportadas. O Lotus Domino Directory contém usuários e
grupos com diversas visualizações para expor detalhes sobre pessoas e grupos da organização.
Apesar de o aplicativo Lotus Domino Employees ser relativamente simples, os conceitos elaborados
aqui podem ser aplicados em qualquer aplicativo Lotus Domino. Usando um exemplo existente do
Project Zero, concentramo-nos na integração de um servidor Lotus Domino no modelo de programação
Project Zero. O aplicativo foi criado com o candidato M3 para o Project Zero e testado com o
Firefox 2.0.
Sobre o Project Zero
Antes de detalhar o aplicativo Lotus Domino Employees, vamos descrever de forma resumida o
Project Zero. Como o Web site do Project
Zero determina, o Project Zero é "um ambiente de desenvolvimento e execução ágil que usa os
tempos de execução de REST e de script para acelerar e simplificar o desenvolvimento e a
implementação de aplicativos da Web dinâmicos". Project Zero e seu complemento de plug-ins do
Eclipse permitem que usuários montem, construam, testem e implementem rapidamente aplicativos
baseados em REST.
Lotus Domino Ativado para REST Usando Project
Zero
A maioria dos desenvolvedores do Lotus Domino são familiarizados com os agentes do Lotus
Domino gravados em diversas linguagens, especialmente em LotusScript. Por fim, um aplicativo
RESTful, que exibe os princípios REST mencionados anteriormente, pode ser acessado através da
Web. Além do mais, o aplicativo pode ser endereçado através de recursos denominados. A
instanciação de um aplicativo usando uma convenção como LotusScript ou agentes simples se
distancia da base de REST, denominada recursos.
Considere que os agentes do Lotus Domino sejam chamados através da Web usando uma URL
semelhante a http://domino.ibm.com/database.nsf/AgentName?OpenAgent, conforme mostrado na figura
1. Esse é dificilmente o recurso familiar denominado que desejamos alcançar e muitas informações
podem ser passadas como argumentos. Essa implementação ou uma implementação de servlet
equivalente é sinônimo de uma implementação baseada em verbo em vez de nas características
RESTful. Por exemplo, o agente ou servlet pode receber parâmetros, como
?action=create&user=vstaub; uma abordagem RESTful, por outro lado, simplesmente opera
sobre dados de um método POST.
Figura 1. Um Recurso Denominado do Agente Lotus
Domino
Uma implementação mais apropriada pode ser um filtro Lotus Domino Security API (DSAPI).
Filtros DSAPI residem na pilha HTTP do Lotus Domino e podem ser chamados quando uma condição é
atendida na URL. Caso seja familiarizado com o IBM Lotus Quickr, todas as URLs que contêm
/quickr são tratados pelo filtro DSAPI do servidor Lotus Quickr. Usando um filtro DSAPI, a
implementação está em vigor integrada à pilha HTTP do servidor Lotus Domino. Infelizmente, criar
um filtro DSAPI é uma tarefa desanimadora para muitos, pois requer um entendimento do kit de
ferramentas DSAPI e da linguagem de programação C. Se um aplicativo RESTful facilita uma
convenção de recurso denominado /database/document_unid ou /database/view_name, pode operar de
forma transparente com o servidor da Web Lotus Domino existente chamando operações RESTful sob
condições predefinidas. Consulte a figura 2. Dependendo da base do leitor, essa implementação
pode ser muito técnica ou consumir mais tempo para implementar.
Figura 2. Um Recurso Denominado do Filtro DSAPI do Lotus
Domino
Por fim, considere a linguagem Java. Desde o Lotus Domino 6, é possível usar Java para acessar
recursos do Lotus Domino, como bancos de dados, visualizações ou documentos de um aplicativo
ativado para Java. Junte o acesso Java a um servlet facilitando pedidos da Web, e terá uma
solução viável para interagir com recursos do Lotus Domino pela Internet. Conforme informado
anteriormente, no entanto, a implementação do servlet não é puramente RESTful. O recurso RESTful
ativado para a Web de um aplicativo é muito aprimorado usando um projeto incubador cada vez mais
popular, conhecido como Project Zero.
Figura 3. Um Recurso Denominado do Aplicativo Project
Zero
Identificando Recursos
Em um Lotus Domino Directory, podemos identificar os seguintes recursos:
- Employee. Recurso individual sobre a pessoa (equivalente a um documento do Lotus
Notes).
- Employees. Uma coleta de funcionários (equivalente a um coleta de documentos do Lotus
Notes ou a uma visualização do Lotus Notes).
Outro aspecto importante de identificação do recurso é entender como ele pode ser abordado.
Employees estão disponíveis como parte do terminal padrão: http://[hostname]/employees.
Um funcionário pode ser acessado através de um identificador exclusivo, como um nome abreviado
ou um endereço de e-mail: http://[hostname]/employees/[uid].
Representação de Recurso
A troca de dados entre o aplicativo Lotus Domino Employees e o cliente ou navegador é
realizada usando JavaScript Object Notation (JSON). A decisão de usar JSON vem do suporte
existente ao Project Zero e sua provisão de um formato de dados leve de fácil utilização em um
aplicativo JavaScript. Por fim, JSON é usado para representar dados e um usuário no Lotus Domino
Directory pode aparecer como o objeto JSON mostrado na listagem 1.
Listagem 1. Representação JSON de um Funcionário
{
"FirstName": "Van",
"FullName": "CN=Van Staub\/O=IBM",
"HTTPPassword": "(355E98E7C7B59BD810ED845AD0FD2FC4)",
"InternetAddress": "vstaub@ibm.com",
"LastName": "Staub",
"OfficeCity": "Atlanta",
"OfficePhoneNumber": "(123) 456-7890",
"OfficeState": "Ga",
"OfficeStreetAddress": "4111 Northside Pkwy",
"ShortName": "vstaub"
}
|
Como você verá posteriormente neste artigo, a capacidade de usar esses dados no cliente
JavaScript é imediata. Um aplicativo cliente JavaScript recebe JSON como um objeto, através do
qual valores são referidos usando uma sintaxe de ponto (dot notation syntax). Por exemplo, para
acessar o sobrenome do usuário, use a sintaxe object.LastName. Essa sintaxe alivia quaisquer
requisitos de análise e facilita o acesso direto aos dados. Para obter informações adicionais
sobre JSON, consulte o Web site de JSON.
Métodos de Mapeamento
A Tabela 1 ilustra o método HTTP usado para realizar cada um dos casos de uso.
Tabela 1. Tipos de Métodos HTTP de Caso de Uso
| Caso de uso | Recurso | Método HTTP |
|---|
| Visualizar funcionários | Employees | GET |
|---|
| Visualizar funcionário | Employee | GET |
|---|
| Criar funcionário | Employee | POST |
|---|
| Atualizar funcionário | Employee | PUT |
|---|
| Excluir funcionário | Employee | DELETE |
|---|
Códigos de resposta
A Tabela 2 detalha a resposta HTTP para a operação e a resposta do serviço em caso de erro.
Qualquer pedido bem-sucedido obtém uma resposta 200 OK para GET, POST, PUT e DELETE e 201 para
POST, mas a condição de erro aciona a resposta HTTP apropriada.
Tabela 2. Códigos HTTP de Caso de Uso
| Caso de Uso | Falhas |
|---|
| Visualizar funcionários | 401 (não autorizado) 404 (quando os funcionários não podem ser localizados) |
|---|
| Visualizar funcionário | 401 (não autorizado) 404 (quando o UID não pode ser localizado) |
|---|
| Criar funcionário | 401 (não autorizado) 303 (se o UID em questão já existe) |
|---|
| Atualizar funcionário | 401 (não autorizado) 403 (proibido) |
|---|
| Excluir funcionário | 401 (não autorizado) 403 (proibido) |
|---|
Projetando Usando Project Zero
Project Zero permite que desenvolvedores criem rapidamente aplicativos ativados para a Web,
focando REST. Em suma, a combinação de um pouco de programação Java e do Project Zero permite
criar e implementar um aplicativo ou serviço RESTful Lotus Domino. O aplicativo Lotus Domino
Employees usa o aplicativo demo Employees existente do Project Zero para grande parte da lógica
do lado do cliente. Isso permite que o leitor perceba a versatilidade do Project Zero combinada
com nova lógica do lado do servidor específica do Lotus Domino.
Project Zero permite focar a lógica de negócios principal do aplicativo em vez de manipular
pedidos da Web recebidos, analisar URLs e manipular diversos métodos. Há duas opções para
implementar aplicativos Project Zero: PHP e Groovy. A implementação Groovy complementa a
capacidade de acessar recursos do Lotus Domino usando Java. Essencialmente, é possível gravar
aplicativos Groovy que acessam os recursos do Lotus Domino diretamente, usando Java no código
Groovy ou chamando funções de uma biblioteca Java existente. Optando por implementar em Groovy,
é possível utilizar um plug-in do Eclipse para facilitar a criação e teste do aplicativo.
Novamente, isso permite concluir o processo de criação, implementação e testes facilmente.
No fundo, o aplicativo RESTful Lotus Domino e a maioria dos aplicativos Project Zero têm um
design RESTful. Project Zero permite criar um arquivo Groovy, um manipulador, para funcionar
como o recurso denominado. O cliente pode, então, passar um recurso denominado virtual ao
manipulador. Por exemplo, você cria um script de manipulador denominado employees.groovy.
Através de uma URL, o usuário acessa, então, o recurso denominado /employees. Um pedido para
/employees pode, então, atender todo o conteúdo do diretório para o cliente. Um pedido de URL
semelhante é /employees/username. O membro do nome de usuário é um recurso virtual. O arquivo
employees.groovy permite acesso ao valor do nome de usuário, que, por sua vez, manipulam de
forma apropriada os detalhes da implementação. Observe a correlação entre o recurso denominado
virtual e o nome do arquivo do manipulador Groovy. Os detalhes da implementação do manipulador
imitam a arquitetura REST. As operações, como criar, atualizar, recuperar e excluir (CRUD) são
facilitadas através de funções correspondentes no manipulador Groovy, conforme mostrado na
tabela 3.
Tabela 3. Definindo os Manipuladores Groovy
| Tipo de Método | URL | Função do manipulador Groovy |
|---|
| GET | /employees | onList() |
|---|
| POST | /employees | onCreate() |
|---|
| GET | /employees/[uid] | onRetrieve() |
|---|
| PUT | /employees/[uid] | onUpdate() |
|---|
| DELETE | /employees/[uid] | onDelete() |
|---|
Apesar de grande parte das informações que discutimos focar o lado do servidor, Project Zero
também facilita a criação de aplicativo do lado do cliente. A estrutura Ajax popular, Dojo, é
empacotada como uma biblioteca de complemento. Assim, é possível criar pedidos de serviços
recebidos e aplicativos da Web ativados para Ajax.
Caso opte por usar o Project Zero, é possível trabalhar com um aplicativo e arquitetura de
desenvolvimento interessante de ponta que incorpora tudo, desde o Eclipse até o tão divulgado
Web 2.0.
Além disso, Project Zero oferece conversão implícita de objetos em uma anotação JavaScript,
JSON. Podemos fornecer facilmente a resposta ao cliente como um objeto Java, que é então
convertido automaticamente nas representações JSON. É fácil explorar os recursos de conveniência
da plataforma Project Zero.
O aplicativo Lotus Domino Employees é composto por uma estratégia de implementação em camadas:
um aplicativo cliente, o aplicativo Project Zero, uma coleta de classes Java e, por fim, o
próprio servidor Lotus Domino, conforme mostrado na figura 4.
Figura 4. Modelo do Aplicativo Lotus Domino
Employees
O cliente, um aplicativo baseado na Web JavaScript ou um serviço customizado, conecta ao
aplicativo Project Zero. Project Zero é responsável por qualquer interação com o cliente
referente ao processamento do pedido recebido, à localização do recurso denominado e o envio da
resposta apropriada. Project Zero elimina o gasto adicional necessário para manipular e
processar o pedido da Web recebido. Ao usar as funções inerentes do Project Zero que manipulam
as operações CRUD, você fica livre de grande parte da codificação normalmente envolvida no
aplicativo de servidor da Web.
As classes Java são responsáveis por interagir com o servidor Lotus Domino. Na essência, as
classes Java são a lógica do aplicativo Lotus Domino Employees, que é nada mais do que uma
coleta de funções do assistente. Esses assistentes podem utilizar a API Java do Lotus Domino, o
archive notes.jar, para interagir com os dados armazenados no Lotus Domino Directory.
Você poderia gravar tão facilmente código que permite que classes Groovy interajam com o Lotus
Domino, mas preferimos separar a lógica do aplicativo como funções assistentes nas classes Java.
Como as classes Java são acopladas fracamente ao Project Zero, o aplicativo pode ser reutilizado
em outros cenários -- em um rich client ou servlet, por exemplo. De forma semelhante, os
aplicativos gravados em Java que acessam o servidor Lotus Domino podem ser facilmente
incorporados à plataforma Project Zero para fornecer uma entrega ativada para a Web.
Comportamento do Aplicativo
Vamos considerar o fluxo de operações de qualquer aplicativo Lotus Domino usando a estratégia
descrita anteriormente. Suponhamos que uma operação do cliente faça uma chamada assíncrona ao
aplicativo Project Zero. Project Zero faz pouco mais do que receber o pedido e iniciar a chamada
do código Java necessário para facilitar a operação necessária. As classes Java interagem com
dados no servidor Lotus Domino. O objeto Java pode ser então serializado e enviado de volta ao
solicitante.
O aplicativo Lotus Domino Employees consiste em interações muito simples com o Lotus Domino
baseadas na operação recebida para um usuário:
- Recuperar informações sobre o documento da pessoa.
- Excluir o documento da pessoa.
- Registrar um novo usuário.
- Atualizar o documento da pessoa.
A Tabela 4 detalha o comportamento do servidor Lotus Domino.
Tabela 4. Definindo o Comportamento do Lotus
Domino
| Tipo de método | URL | Função do manipulador Groovy | Comportamento do Lotus Domino |
|---|
| GET | /employees | onList() | Recuperar informações sobre o(s) documento(s) da pessoa |
|---|
| POST | /employees | onCreate() | Registrar um novo usuário |
|---|
| GET | /employees /[uid] | onRetrieve() | Recuperar informações sobre o documento da pessoa |
|---|
| PUT | /employees/[uid] | onUpdate() | Atualizar o documento da pessoa |
|---|
| DELETE | /employees/[uid] | onDelete() | Excluir o documento da pessoa |
|---|
Usando Segurança do Lotus Domino
Para abordar os interesses de segurança, usamos um mecanismo existente do Domino, Multi-Server
Single Sign On (SSO). Após um usuário autenticar com êxito no Lotus Domino através da Web, o
servidor Lotus Domino emite um token criptografado no formato de um cookie para o navegador. O
valor no cookie pode ser usado para autenticação. Dessa maneira, reutilizamos o token
criptografado a partir do cookie para conectar ao Lotus Domino no aplicativo Project Zero. Isso
tem um efeito de proteção duplo de acesso ao aplicativo da Web Project Zero:
- Assegura que somente usuários válidos podem usar o aplicativo (autenticação).
- Assegura que o usuário acessando o Lotus Domino obtenha somente dados para os quais ele ou
ela está aprovado (autorização).
Project Zero ativou recentemente o suporte para o novo Lotus Domino LTPAToken. A incorporação
do valor de LTPAToken do cookie permite criar uma sessão do Lotus Notes baseada na identidade do
usuário. A criação da sessão do Lotus Notes é o ponto a partir do qual toda a interação com o
Lotus Domino inicia.
Para tirar proveito do LTPAToken, um administrador configura o servidor para SSO. Isso pode
ser feito no IBM Lotus Domino Administrator ou no Lotus Notes Client, criando um documento de
Configuração de SSO da Web, conforme mostrado na figura 5.
Figura 5. Criando o Documento de Configuração do SSO da Web do
Lotus Domino
Em seguida, configure o servidor do Lotus Domino para usar o documento de Configuração do SSO
da Web no documento do servidor, atualizando o método de autenticação da Sessão para Diversos
Servidores (SSO), usando a configuração de SSO da Web que acaba de criar. Consulte a figura
6.
Figura 6. Configurando o Lotus Domino para SSO
Observe que o LTPAToken gerado pelo servidor Lotus Domino é válido somente para o domínio DNS
listado no documento de configuração do SSO da Web. Além do mais, o LTPAToken é passado somente
a servidores acessados usando o domínio no documento de Configuração de SSO da Web.
Essencialmente, isso significa que você deseja acessar o aplicativo da Web Lotus Domino
Employees usando a mesma URL usada para acessar o servidor Lotus Domino. Não use os nomes de
host locais nem os endereços IP.
Para obter um LTPAToken, efetue login no servidor Lotus Domino, conforme mostrado na figura 7.
Figura 7. Criando o LTPAToken no Navegador
Verifique se você tem um LTPAToken inserindo a seguinte URL na barra de endereço do navegador:
javascript:alert(document.cookie)
Consulte a figura 8.
Figura 8. Confirmado que Haja um LTPAToken
Usando o Objeto de Sessão do Lotus Notes
Toda a interação com o Lotus Domino usando as classes Java deriva do objeto de sessão. A
partir do objeto de sessão, o programador pode iniciar operações poderosas, como abrir bancos de
dados, enviar comandos do console, recuperar pares nome/valor do Notes.ini e registrar novos
usuários. No aplicativo Lotus Domino Employees, o objeto de sessão é construído usando o
LTPAToken passado no aplicativo a partir do navegador. Esse processo permite que o aplicativo
execute somente operações permitidas para o usuário que efetuou login.
Vale a pena mencionar os detalhes por trás da obtenção do objeto de sessão do Lotus Notes. O
objeto pode variar na implementação, dependendo do ambiente de desenvolvimento, assim como da
intenção de um aplicativo implementado. O Lotus Domino
Designer Programming Guide, Volume 3 Java CORBA Classes descreve as diferenças na obtenção
de um objeto de sessão do Lotus Notes.
O objeto de sessão do Lotus Notes pode ser criado em dois formatos: usando a Chamada de
Procedimento Remoto (RPC) ou usando o Internet Inter-ORB Protocol (IIOP). Chamadas RPC requerem
que o Lotus Notes Client, o IBM Lotus Domino Designer ou o servidor Lotus Domino esteja
instalado localmente com relação ao aplicativo em execução. O aplicativo Lotus Domino Employees,
um exemplo desse formato, cria uma sessão local para o servidor Lotus Domino em execução. Essa
opção tem a intenção de maximizar o desempenho para fornecer uma interface da Web responsiva.
Configurando Project Zero para Sessões RPC
Para executar qualquer programação Java do Lotus Notes, a biblioteca Java aplicável do Lotus
Notes deve ser incluída no caminho da classe do projeto. Ao usar chamadas RPC, inclua o archive
notes.jar no Caminho de Construção Java de seu aplicativo. Ao executar seu aplicativo Project
Zero pela primeira vez, você pode receber um erro mostrado na figura 9.
Figura 9. A Biblioteca Java do Lotus Notes Está
Ausente
Essencialmente, esse erro significa que a chamada nativa à biblioteca nlsxbe não pôde ser
localizada. Para corrigir o erro, você deve incluí-la na variável java.library.path do
aplicativo Project Zero. A biblioteca notes.jar faz as chamadas nativas a funções no diretório
do programa Lotus Domino. Funções nativas, por sua vez, chamam outras funções nativas. Caso
tenha executado qualquer programação Java anterior ao Lotus Notes no Eclipse, pode estar ciente
de que a solução mais fácil é incluir o diretório do programa Lotus Domino ou Lotus Notes na
variável de ambiente PATH do sistema. No Project Zero, os requisitos são ligeiramente
diferentes. Para resolver o erro anterior, inclua o caminho no diretório do programa Lotus
Domino ou Lotus Notes na configuração do tempo de execução de seu aplicativo Project Zero,
conforme mostrado nas figuras 10 e 11.
Selecione a guia Argumentos da caixa de diálogo Executar conforme mostrado na figura 10.
Então, na área de janela Argumentos VM, anexe o caminho da instalação do Lotus Domino ou do
Lotus Notes no argumento java.library.path:
-Djava.library.path="${ZERO.NATIVES};C:/Lotus/Domino"
Lembre-se de colocar um ponto e vírgula para separar quaisquer argumentos existentes do novo
caminho de instalação incluído do Lotus Domino ou do Lotus Notes.
Figura 10. Configurando o Argumento VM do Lotus
Domino
Selecione a guia Ambiente da caixa de diálogo Executar conforme mostrado na figura 11. Edite a
variável PATH na lista e, na caixa de diálogo Editar Variável de Ambiente que aparece, anexe o
caminho da instalação do Lotus Domino ou do Lotus Notes.
Novamente, lembre-se de colocar um ponto e vírgula para separar quaisquer argumentos
existentes do novo caminho de instalação incluído do Lotus Domino ou do Lotus Notes.
Figura 11. Configurando o Valor da Variável PATH do Lotus
Domino
Criando uma Sessão RPC
Supondo que o usuário já tenha autenticado o servidor Lotus Domino, os arquivos Groovy passam
o LTPAToken à classe Java SessionHelper.
Session session= SessionHelper.getInstance()
.getSession(zget("/request/cookies/in").get("LtpaToken"));
A classe SessionHelper, por sua vez, cria o objeto de sessão do Lotus Notes, conforme mostrado
na lista 2.
Listagem 2. Criação do objeto de sessão do Lotus Notes
// verify that the Zero HTTP thread has been properly
// initialized for Notes RPC communication
Long threadId= new Long(NotesThread.currentThread().getId());
System.out.println("Zero thread : " + threadId + " using LtpaToken : " + ltpaToken);
...
// already created the NotesThread?
if(sessions.containsKey(threadId)){
// not really an error
System.err.println("NotesThread already initialized");
} else {
System.out.println("Initializing NotesThread");
// initialize the NotesThread
NotesThread.sinitThread();
}
// create a Notes Session
// use null to indicate an RPC connection to the
// server on which the Project Zero application runs
Session session= NotesFactory.createSession(null, ltpaToken);
System.out.println("Storing NotesSession for Zero thread : " + threadId);
// cache the session for future use
sessions.put(threadId, session);
System.out.println("NotesSession created for user " + session.getUserName());
return session;
... |
Ao fazer chamadas RPC, o objeto NotesThread deve ser inicializado antes de utilizar a sessão.
Essa etapa não é necessária para implementação de IIOP. Você também deve chamar a função
stermThread no final do processamento para evitar quaisquer encerramentos anormais de afetarem o
servidor Lotus Domino em execução. Quando um objeto de sessão é obtido, pode ser usado para
interagir com o servidor Lotus Domino usando o nível de controle de acesso concedido ao usuário
definido pelo LTPAToken.
Grande parte do tempo investimos no projeto envolvido determinando como tratar dos objetos
Lotus NotesThread. O aplicativo Project Zero usa três threads separados, por padrão, para tratar
de pedidos HTTP recebidos de maneira round-robin. Cada um desses pedidos deve ser inicializado
corretamente pela classe NotesThread antes de prosseguir para interagir com o Lotus Domino.=Não
fazer isso geralmente resulta no erro mostrado na listagem 3.
Listagem 3. Erro de inicialização incorreta do
NotesThread
Caused by: java.lang.UnsatisfiedLinkError: NCreateSessionWithTokenOrName
at lotus.domino.local.Session.NCreateSessionWithTokenOrName(Native Method)
at lotus.domino.local.Session.createSessionWithTokenOrName(Unknown Source)
at lotus.domino.NotesFactory.createSessionC(Unknown Source)
at lotus.domino.NotesFactory.createSession(Unknown Source)
at com.ibm.devworks.SessionHelper.createSession(SessionHelper.java:24)
at com.ibm.devworks.SessionHelper.getSession(SessionHelper.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.codehaus.groovy.runtime.metaclass.ReflectionMetaMethod.invoke
(ReflectionMetaMethod.java:56)
at org.codehaus.groovy.runtime.MetaClassHelper.doMethodInvoke
(MetaClassHelper.java:599)
at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1030)
at org.codehaus.groovy.runtime.Invoker.invokeMethod(Invoker.java:69)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:66)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN
(ScriptBytecodeAdapter.java:165)
at employees.onList(employees.groovy:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.codehaus.groovy.runtime.metaclass.ReflectionMetaMethod.invoke
(ReflectionMetaMethod
|
UnsatisfiedLinkError indica que NotesThread não foi inicializado corretamente.
Os threads HTTP, uma vez inicializados, devem ser eliminados corretamente. A eliminação é
facilitada pela função NotesThread.stermThread(). Nossa intenção é inicializar o thread HTTP
Zero quando o pedido recebido for recebido no Zero e, subsequentemente, eliminar NotesThread
antes de renderizar a saída. Consulte a listagem 4.
Listagem 4. Eliminando o Objeto de Sessão e NotesThread
def onList() {
try {
// create a Session from the SessionHelper
// all Domino operations require a Session
Session session= SessionHelper.getInstance()
.getSession(zget("/request/cookies/in").get("LtpaToken"));
...
} catch (NotesException e) {
request.status = HttpURLConnection.HTTP_INTERNAL_ERROR
request.error.message = e.getMessage()
request.view = "error"
}
// properly dispose of any Domino objects by using the
// SessionHelper
SessionHelper.getInstance().shutdown();
// finally render the content to the client
render()
}
/**
* Properly dispose of any remaining Sessions or NotesThreads.
*
*/
public void shutdown(){
System.out.println("Closing NotesSession ...");
// get the Zero thread requesting Notes shutdown
Long threadId= new Long(NotesThread.currentThread().getId());
try {
Session session= (Session)sessions.get(threadId);
System.out.println("Closing NotesSession for user " + session.getUserName());
session.recycle();
System.out.println("NotesSession closed");
} catch (NotesException e) {
e.printStackTrace();
} finally {
// terminate the NotesThread properly
NotesThread.stermThread();
// remove a the so a NotesThread can be initialized
// on the Zero thread
sessions.remove(threadId);
System.out.println("Removed NoteSession for Zero thread : " + threadId)
System.out.println("Removed NoteSession for Zero thread : " + threadId);
}
}
|
Esse modelo provou ser bem desafiador. Em alguns momentos, NotesThreads foram encerrados
corretamente enquanto outros pedidos causaram travamento da JVM. Os travamentos mostrados na
listagem 5 foram vistos durante o andamento da programação.
Listagem 5. Conteúdo de Erro de Travamento da JVM
#
# An unexpected error has been detected by HotSpot Virtual Machine:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x60001457, pid=2660, tid=6448
#
# Java VM: Java HotSpot(TM) Client VM (1.5.0_12-b04 mixed mode)
# Problematic frame:
# C [nnotes.dll+0x1457]
#
|
Esses erros foram atribuídos à inicialização de um NotesThread em um thread HTTP Zero já
inicializado ou à tentativa de encerrar um NotesThread em um thread HTTP Zero inicializado.
Enfrentamos um dilema entre inicializar e eliminar NotesThreads corretamente e deixar os threads
inicializados, mas resultar em um servidor Lotus Domino possivelmente instável. Optamos pela
segunda opção para propósitos de demonstração para o artigo. Há algumas maneira de combater esse
problema de design. É possível estender a classe NotesThread e encapsular sua lógica na mesma.
Quando o método run() ou runNotes() for concluído, o NotesThread será eliminado de forma
oportuna, mas pode ser necessário implementar threads que executam operações muito específicas.
A opção para design é uma operação interessante e pode-se postar questões nos fóruns do Project Zero para obter
assistência da equipe do Project Zero e de outros da comunidade.
A intenção aqui não é impedir que você explore o Project Zero e o Lotus Domino, mas informar
sobre nossa experiência. Pode haver soluções alternativas ou limitações técnicas conhecidas para
os problemas descritos neste artigo.
Observe, também, que o aplicativo cria uma sessão local do Notes, mas não está limitado a
acessar dados no servidor local nem no Lotus Notes Client. É possível atualizar código para
acessar bancos de dados em servidores Lotus Domino remotos, especificando o nome do servidor
Lotus Domino na função getDatabase().
Para obter detalhes adicionais, consulte a seção "Usando o Aplicativo Lotus Domino Employees"
mais adiante neste artigo.
Criando uma Sessão IIOP
Apesar de não estar implementado no aplicativo Lotus Domino Employees, IIOP é uma alternativa
para o formato RPC. IIOP pode ser desejável quando um aplicativo Project Zero não estiver em
execução em um servidor com uma instalação do servidor Lotus Domino local ou do Lotus Notes
Client. Você compensa a necessidade de uma instalação local do Lotus Domino ou do Lotus Notes
com a necessidade de executar a tarefa DIIOP no servidor Lotus Domino. A tarefa DIIOP facilita
as conexões remotas que acessam bancos de dados, visualizações, documentos e mais.
O código RPC pode ser atualizado, conforme mostrado na listagem 6 para facilitar a
conectividade IIOP com o Lotus Domino.
Listagem 6. Código de Conexão IIOP Difere
private static Session createSession(String server, String token) {
System.out.println("Creating Session");
try {
// server should be a DNS address or IP
Session s = NotesFactory.createSession(server, token);
System.out.println("Creation successful");
return s;
} catch (NotesException e) {
System.err.println("Creation failed");
e.printStackTrace();
return null;
}
}
|
Observe que a única mudança substancial é a remoção de processamento do NotesThread. Ao usar
IIOP, a sessão NotesThread não é mais necessária.
IIOP introduz novas considerações de configuração no servidor Lotus Domino: segurança, acesso
ao arquivo diiop_ior.txt no servidor Lotus Domino e diversas configurações de porta. Deve-se
assegurar também que a opção "Permitir que clientes HTTP naveguem pelos bancos de dados"
mostrada na figura 12 esteja selecionada na guia Protocolos da Internet - HTTP do documento
Servidor Lotus Domino.
Figura 12. Configurando DIIOP
Essa configuração permite que a sessão obtenha uma lista de bancos de dados no servidor. Para
obter informações adicionais sobre DIIOP, consulte a seção NotesFactory do Lotus Domino Designer
Programming Guide.
Acessando Dados do Lotus Domino
Agora que foi estabelecido o comportamento do aplicativo Lotus Domino Employees, as funções
assistentes, usando a sessão do Notes, iniciam a consulta ou modificação do diretório Lotus
Domino. Como o foco do aplicativo Lotus Domino Employees é específico para usuários, as funções
assistentes operam nos documentos das pessoas do Lotus Domino.
Por exemplo, o pedido ao recurso /employees recupera todos os contatos do diretório. Essa ação
é equivalente à obtenção de todos os documentos que foram criados com o formulário Pessoa no
names.nsf do banco de dados. O código da listagem 7 ilustra esse comportamento.
Listagem 7. Obtendo todos os Funcionários Usando Coletas de
Documentos do Lotus Notes
public Employees getAllPeople() {
// conduct a search for people created with the Form People
// this is true for all users
DocumentCollection dc= searchNab("Form=\"Person\"");
// convert the collection into Employees
Employees contacts= getPeople(dc);
// recycle the document collection
try {
dc.recycle();
} catch (NotesException e) {
e.printStackTrace();
}
return contacts;
}
|
Observe que a função getAllPeople envia uma fórmula de procura ao NAB para obter todos os
documentos das pessoas, o que é idêntico à procura que um usuário do cliente pode realizar em um
banco de dados do Lotus Domino. Em vez de abrir o diretório e realizar a procura, é possível
abrir a visualização Pessoas no diretório e retornar DocumentCollection na mesma. Essa abordagem
permite usar melhor as estruturas existentes do Lotus Domino para reduzir o gasto adicional de
código e desempenho. Também alivia o requisito de um diretório que seja indexado por texto
completo.
Representação de Dados do Lotus Domino
Na recuperação anterior para obter todos os funcionários, a estrutura retornada é um objeto do
Notes, DocumentCollection. DocumentCollection está denominado corretamente; consiste em uma
coleta de objetos dos documentos. O objeto do documento corresponde ao documento da pessoa do
diretório. Para tornar o processo de representação de dados claro, primeiro copiamos os valores
necessários do documento para um novo objeto Employee, conforme mostrado na listagem 8.
Listagem 8. Conversão de Objeto de Document para
Employee
public Employee(Document doc){
data= new HashMap<String, String>();
try {
// verify that the document is a person doc
if(doc != null &&
doc.hasItem("Form") &&
doc.getItemValueString("Form").
equalsIgnoreCase("Person")){
// pull data as Strings from the person doc
for(int i= 0; i < Employee.FIELDS.length; i++){
data.put(Employee.FIELDS[i], doc.getItemValueString(
Employee.FIELDS[i]));
}
notesUrl= doc.getNotesURL();
}
} catch (NotesException e) {
e.printStackTrace();
notesUrl= "";
}
}
|
O código itera sobre os nomes de campo predefinidos (mostrado na listagem 9) especificados no
objeto Employee e copia o valor do campo correspondente no documento da pessoa em um HashMap
contido no objeto employee.
Listagem 9. Iterando Nomes de Campos
public static final String NAME= "FullName";
public static final String UID= "ShortName";
public static final String FIRSTNAME= "FirstName";
public static final String LASTNAME= "LastName";
public static final String EMAIL= "InternetAddress";
public static final String PHONE= "OfficePhoneNumber";
public static final String PASSWORD= "HTTPPassword";
public static final String ADDRESS= "OfficeStreetAddress";
public static final String CITY= "OfficeCity";
public static final String STATE= "OfficeState";
public static final String ZIP= "OfficeState";
|
Essencialmente, imitamos os pares nome/valor contidos no objeto do documento no objeto
Employee. Em um sistema de grande escala, copiar os dados reais protege contra a possibilidade
do objeto Lotus Domino ser reciclado ou removido antes do processo de conversão JSON ser
iniciado, o que pode resultar em um erro.
Convertendo Dados do Lotus Domino para
JSON
Considere o estado do aplicativo quando um objeto Employee é preenchido com dados do usuário
e, subsequentemente, precisa convertê-los para JSON e enviar JSON ao cliente. Esse processo
ocorre na recuperação de um usuário usando o pedido employees/[uid]. Mais uma vez, Project Zero
torna isso extremamente fácil, conforme mostrado na listagem 10.
Listagem 10. Project Zero Possui de Forma Inerente Conversão
JSON
// retrieve the Employees Collection by creating a
// NabHelper and requesting all the people
Employees employees= new NabHelper(session).getAllPeople();
if(employees != null){
// automatically serialize the object to JSON using
// Project Zero's custom converter
request.view='JSON'
request.json.output= employees;
}
render()
|
A etapa chave no código anterior é fornecer o objeto real como saída JSON para o cliente. Para
objetos simples, Project Zero converte automaticamente o objeto em JSON usando as funções
públicas get. Para objetos mais complexos, deve-se definir o processo de conversão usando um
conversor customizado.
Convertendo os Dados do Lotus Domino Usando um Conversor
Customizado
Para realizar a conversão de forma implícita usando a sintaxe request.json.output = object,
criamos um conversor customizado. Considerando um objeto, Project Zero instancia o conversor
customizado apropriado para converter o objeto em JSON. Para permitir isso, crie uma classe que
implemente a interface IConverter (Milestone 1) ou Converter (Milestone 2). Nossa classe é
fornecida na listagem 11.
Listagem 11. Um Conversor de Cliente de Funcionário
public class EmployeeConverter implements Converter {
public Object toJson(Object o) {
Employee person = (Employee) o;
JSONObject json = new JSONObject();
// the person document's fieldname value pairs have already been
// stored as a hashmap when the document was originally read
// simply convert the contents into JSON
Iterator it= person.getData().
keySet().iterator();
while(it.hasNext()){
String param= (String)it.next();
json.put(param,
(String)person.getData().get(param));
}
return json;
}
...
|
O objeto recebido na designação request.json.output é fornecido como um argumento na função
toJson. Criamos então um JSONObject para armazenar os pares nome/valor armazenados no momento no
objeto Employee. A representação de JSONObject de um contato aparece conforme mostrado na
listagem 12.
Listagem 12. Representação JSON de Dados no Documento da
Pessoa
{
"FirstName": "Van",
"FullName": "CN=Van Staub\/O=IBM",
"HTTPPassword": "(355E98E7C7B59BD810ED845AD0FD2FC4)",
"InternetAddress": "vstaub@ibm.com",
"LastName": "Staub",
"OfficeCity": "Atlanta",
"OfficePhoneNumber": "(123) 456-7890",
"OfficeState": "Ga",
"OfficeStreetAddress": "4111 Northside Pkwy",
"ShortName": "vstaub"
}
|
O JSONObject não se limita a pares nome/valor. É possível criar objetos complexos usando
cadeias de caracteres, números, valores, arrays e outros objetos. Por exemplo, a listagem 13 é
uma representação dos bancos de dados em um servidor Lotus Domino. O JSONObject contém um array
(JSONArray) de JSONObjects contendo informações do banco de dados. Cada objeto também contém um
status de erro e uma mensagem de erro.
Listagem 13. Uma Representação Complexa de Bancos de Dados do
Lotus Domino
{
"databases": [
{
"filename": "names.nsf",
"filepath": "names.nsf",
"httpurl": "http:\/\/domino.ibm.com\/__85257350001864E6.nsf?OpenDatabase",
"message": "",
"notesurl": "notes:\/\/Domino@IBM\/__85257350001864E6.nsf?OpenDatabase",
"replicaid": "85257350001864E6",
"status": 0,
"template": "StdR4PublicAddressBook",
"title": "IBM's Directory"
},
{
"filename": "webadmin.nsf",
"filepath": "webadmin.nsf",
"httpurl": "http:\/\/domino.ibm.com\/__85257350001883E1.nsf?OpenDatabase",
"message": "",
"notesurl": "notes:\/\/Domino@IBM\/__85257350001883E1.nsf?OpenDatabase",
"replicaid": "85257350001883E1",
"status": 0,
"template": "",
"title": "Domino Web Administrator (7)"
}
],
"message": "",
"status": 0
}
|
Configurando um Conversor Customizado
Agora que um conversor customizado foi implementado, é necessário conectar ao objeto e ao
conversor. Isso é feito atualizado o arquivo de configuração do Project Zero, zero.config. Para
conectar um conversor a um objeto, use a seguinte sintaxe:
[/config/json/converters/object=convert_class
Por exemplo, para conectar o objeto Employee ao conversor de funcionário, use a seguinte
configuração:
/config/json/converters/com.ibm.devworks.Contact=com.ibm.devworks.json.
EmployeeConverter
Se optar por implementar conversores para classes do Lotus Notes em si, esteja ciente do tipo
de objeto retornado. Conforme indicado anteriormente, é possível criar tipos variados de Sessões
para acessar dados do Lotus Domino. Dependendo da conexão da sessão, o tipo de dados do Lotus
Domino retornado pode ser diferente. Para assegurar comportamento consistente, você pode querer
configurar os conversores customizados para abranger diversos tipos do mesmo recurso do Lotus
Domino. Consulte a listagem 14.
Listagem 14. Diversos Tipos de Objetos do Lotus Domino que
Requerem um Único Conversor
config/json/converters/lotus.domino.Database=
com.lotus.rest.json.converters.DatabaseConverter
config/json/converters/lotus.domino.local.Database=
com.lotus.rest.json.converters.DatabaseConverter
config/json/converters/lotus.domino.cso.Database=
com.lotus.rest.json.converters.DatabaseConverter
|
Usando o Aplicativo Lotus Domino
Employees
Para usar o aplicativo Lotus Domino Employees, é necessário instalar o Eclipse e o plug-in do
Project Zero no servidor Lotus Domino. Após terem sido instalados, siga estas etapas para
iniciar o uso do aplicativo:
- No Eclipse, escolha Arquivo - Importar - Geral - Projetos Existentes na Área de Trabalho e
selecione então a opção Selecionar Arquivo Archive.
- Clique em Procurar para localizar o arquivo employee.domino.demo.-all-1.0.zip e clique então
em OK.
- Clique em Concluir para importar o projeto selecionado.
- Crie uma nova Configuração de Tempo de Execução escolhendo Executar - Executar como -
Aplicativo Project Zero. Após ter iniciado, pare o aplicativo usando o ícone Parar na
visualização do console.
- Edite a Configuração de Tempo de Execução escolhendo Executar - Executar - Aplicativo
Project Zero - employee.domino.demo. Edite as variáveis java.library.path e PATH localizadas
nas guias Argumentos e Ambiente, respectivamente, e referidas na seção "Configurando Project
Zero para Sessões RPC" neste artigo. Clique em Aplicar e feche então.
- Abra o arquivo config/zero.config.
- Atualize as configurações nas sub-rotinas config/domino/rest para funcionarem com seu
servidor Lotus Domino. Consulte o código na listagem 15.
Listagem 15. Configurando o Aplicativo Lotus Domino
Employees
# mail directory of the Domino server relative
# to the data directory
# during contact creation a mail file is also created
/config/domino/rest/mailDirectory = "mail"
# field that uniquely identifies people
# this should conform to the value passed using REST
# for example, /employees/[uid] is /employees/vstaub
/config/domino/rest/employeeSearchField = "ShortName"
# certifier ID password
/config/domino/rest/certIdPassword = "password"
|
- Novamente, escolha Executar - Executar como - Aplicativo Project Zero. Uma mensagem, como
"C:/Eclipse_ProjectZero/Workspace/employee.domino.demo em execução na porta 8080", aparece
quando o aplicativo está em execução.
- Solicite um recurso protegido do Lotus Domino, como names.nsf.
- Efetue login no servidor Lotus Domino.
- Solicite http://<domino_server_fqdn>:8080.
- Clique em Listar Funcionários para iniciar.
Observe que names.nsf deve estar indexado por texto completo. É possível realizar isso a
partir da caixa Propriedades do banco de dados names.nsf usando um Lotus Notes Client. O cliente
Firefox também produziu o uso mais estável do lado do cliente dos widgets Dojo. Se tudo for
bem-sucedido, você verá o aplicativo Lotus Domino Employee mostrado na figura 13 em seu
navegador.
Figura 13. Uma Implementação Bem-sucedida do Aplicativo Lotus
Domino Employees
A criação de log foi implementada como instruções System.out e System.err. Se ocorrerem
problemas, consulte o log do console para obter informações.
Dicas Gerais
Use a depuração do Eclipse. Revise as variáveis de parâmetros do Contexto Global ao depurar
informações úteis sobre o aplicativo em execução. Usando a perspectiva de depuração ficou
confirmada nossa suspeita de que diversos threads foram usados para facilitar pedidos HTTP com
cada thread necessitando de inicialização do Lotus Notes.
Consulte a documentação. Mudanças em Milestone 1 para Milestone 3 requerem a portabilidade de
código mais antigo. Saiba qual versão você instalou e a versão de quaisquer exemplos que esteja
consultando.
Inicie com um exemplo. Experimente novos recursos ou integração, iniciando com um exemplo
funcional da equipe do Project Zero.
Teste o código em um aplicativo separado. Erros podem ser um fator de nuances da JVM ou do
Project Zero, não necessariamente seu código. Essa abordagem ajuda você a entender o problema e
possivelmente adaptar-se a trabalhar com o Project Zero.
Próximas Etapas
Os conceitos demonstrados neste artigo têm um caso de uso específico; no entanto, o modelo
subjacente é uma modelagem de recurso do Lotus Domino usando Project Zero. É possível assim
representar todos os dados do Lotus Domino usando JSON e aprimorando muito a usabilidade de um
aplicativo existente. Algumas ideias gerais podem ser gravar uma página do IBM Lotus Domino Web
Access compatível com Ajax que recupere automaticamente o arquivo de mensagens do usuário e
exibir isso dinamicamente na página. Outra ideia é criar mais listas responsivas de
visualizações e documentos do Lotus Domino em um ambiente IBM WebSphere Portal. É incrível como
Project Zero facilita colocar uma nova interpretação do Web 2.0 em conceitos existentes do Lotus
Domino.
Conclusão
Em suma, pegamos um banco de dados do Lotus Domino simples e transformamos o mesmo em um
aplicativo RESTful funcional usando Project Zero. Como vimos anteriormente, o uso de linguagem
de script, como Groovy, juntamente com a estrutura do Project Zero aprimorou muito o processo de
desenvolvimento. Por fim, vemos o resultado de um aplicativo Domino baseado em REST. Devido à
popularidade dos conceitos REST e Web 2.0, qualquer desenvolvedor do Lotus Domino pode usar os
conceitos estabelecidos de projetar e implementar o aplicativo RESTful Domino usando Project
Zero. Ao fazer isso, é possível expandir o uso de qualquer aplicativo Lotus Domino de maneiras
novas e interessantes.
Download | Nome | Tamanho | Método de download |
|---|
| employee.domino.demo-all-1.0.zip | 9879KB | HTTP |
Recursos Aprender
Obter produtos e tecnologias
Discutir
Sobre os autores  | |  | Van Staub works for IBM as the technical team lead for the IBM Lotus Domino Portal Integration team. Primarily, Van and his team integrate the following IBM products: IBM Lotus Sametime, IBM Lotus Domino, IBM Lotus Quickplace, IBM Lotus Quickr, and IBM WebSphere Portal. In his free time, Van enjoys fishing, traveling, and spending time with his wife and two dogs. For more information on Van and his interests, you can find related content on his developerWorks blog and developerWorks space.
|
 | |  | Raj Balasubramanian is a Consulting IT Architect for IBM Software Group. He works on customer engagements delivering application and infrastructure related projects. His interests range from anything technical to history and physics. During his copious spare time, he enjoys dating his wife and talking about robots with his sons. You can read about his technical and personal escapades on his personal blog Gurukulam. |
Avalie esta página
|