Evitar pedir usuário e senha em produção no WLS

Quando você realiza a criação de um domínio do WebLogic em modo de produção, ao iniciar o servidor ele solicita à você o usuário e senha administrativos.

 Enter username to boot WebLogic server:
 Enter password to boot WebLogic server:

Para evitar isso e possibilitar a criação de scripts automáticos para inicialização do domínio WebLogic, é necessário criar um arquivo: boot.properties. Crie o arquivo em DOMAIN/servers/AdminServer/security/boot.properties com o seguinte conteúdo:

username=usuario
password=senha

Substitua o “usuario” e “senha” pelo respectiva usuário e senha. Agora é só iniciar o WebLogic e você verá a seguinte linha no log.

<Jan 2, 2012 5:23:22 PM BRST> <Notice> <Security> <BEA-090083> <Storing boot identity in the file: /u01/Oracle/Middleware/user_projects/domains/wc_only_domain/servers/AdminServer/security/boot.properties>

Após o server subir, o arquivo será criptografado e a senha não será mais necessária!

Habilitando Cookies Seguros no WebLogic

Em requisições HTTPS que utilizam cookies é importante habilitar a flag SECURE=”TRUE” nos cookies. Para realizar isso no WebLogic, é necessário adicionar as seguinte linha no weblogic-application.xml

<wls:session-descriptor>
<wls:cookie-secure>true</wls:cookie-secure>
</wls:session-descriptor>

E garantir que no console do weblogic esteja marcado o seguinte: Domain -> Configuration -> Web Application tab, enable “Auth Cookie Enabled”

Para garantir, abrir o config.xml do weblogic e adicionar/alterar a tag:

<auth-cookie-enabled>true</auth-cookie-enabled>

Mais informações: http://www.owasp.org/index.php/OWASP_AppSec_FAQ#What_are_these_secure_cookies.3F

Habilitando o JPA 2 no WebLogic Server

Por padrão o WebLogic Server não vem com o JPA 2 habilitado. Então ao utilizar recursos específicos do JPA 2 dentro do WebLogic Server você pode ter erros semelhantes a esse: java.lang.NoSuchMethodError: javax.persistence.EntityManager.getCriteriaBuilder()Ljavax/persistence/criteria/CriteriaBuilder;

Para resolver esse problema é necessário colocar as libs do JPA 2 no início do classpath do WebLogic. As libs estão disponíveis no caminho $WL_HOME/modules e são as seguintes: javax.persistence_1.0.0.0_2-0-0.jar e com.oracle.jpa2support_1.0.0.0_2-0.jar.

Edite o arquivo setDomainEnv.[sh|cmd] e insira a variável PRE_CLASSPATH da seguinte maneira:

export PRE_CLASSPATH=$MW_HOME/modules/javax.persistence_1.0.0.0_2-0-0.jar:$MW_HOME/modules/com.oracle.jpa2support_1.0.0.0_2-0.jar

No windows, substitua o comando export por set e os dois pontos para ponto e vírgula. Altere o $MW_HOME para o home do middleware. Agora é só realizar deploy do seu aplicativo com JPA 2.

NonCatalogLogger no WebLogic

qrcodeO WebLogic possui um mecanismo de logging com vários recursos, inclusive internacionalização de mensagens de erro. Você pode encontrar informações de como configurar e utilizar de forma detalhada no seguinte endereço: http://download.oracle.com/docs/cd/E12840_01/wls/docs103/i18n/index.html.

O objetivo desse post é utilizar o NonCatalogLogger que é indicado para aplicações que não precisam de internacionalização de log ou para aplicações que executam em sua própria JVM.

««« Clique aqui para ler o restante do conteúdo: NonCatalogLogger no WebLogic »»»

Instalação e Configuração do Oracle ECM

Atenção (19/04/2011): Esse tópico está em revisão e provavelmente sofrerá revisões. Contribuições são bem vindas!

O Oracle Universal Content Management (Oracle UCM) faz parte do Oracle Enterprise Content Management (Oracle ECM) e é utilizado para gerenciamento de conteúdo multi-site.

O primeiro passo é instalar o esquema do Enterprise Content Management utilizando o RCU. Na minha base já está ok. Se você tiver dúvidas de como fazer isso consulte o link Oracle Service Bus e procure por RCU.

Faça o download do Oracle UCM: http://www.oracle.com/technetwork/middleware/content-management/downloads/index-085241.html. Descompacte os dois zips. Acesse a pasta Disk1 e digite o seguinte:

./runInstaller

Informe o caminho do JRE/JDK. O instalador irá abrir.

Oracle Fusion Middleware 11g ECM Suite Installation - Step 1 of 7

Oracle Fusion Middleware 11g ECM Suite Installation - Step 1 of 7

Clique em Next. Escolha Skip Software Updates, se você não tiver Oracle Support, caso contrário, informe e clique em Search For Updates. Nessa versão que estou utilizando no momento não havia nenhum update. Clique em Next. Como eu estou instalando em um Ubuntu e ele não é homologado para softwares da Oracle, nessa próxima etapa haverá alguns erros de pré-requisito. Se você utilizar um SO homologado, verifique os erros ocorridos (se tiver), caso contrário clique em Continue.

Informe o caminho onde está instalado o WebLogic Server. Se você quiser pode alterar o Home Directory. Clique em Install na próxima tela. Aguarde o término da instalação e clique em Next. Clique em Finish.

Oracle Fusion Middleware 11g ECM Suite Installation - Step 7 of 7

Oracle Fusion Middleware 11g ECM Suite Installation - Step 7 of 7

Instalação concluída. Agora é necessário configurar os domínios. Cada aplicação deve ser instalada em seu próprio managed server ou cluster. Para a criação dos domínios, execute o utilitário de configuração de domínio:

./$ECM_ORACLE_HOME/common/bin/config.sh

Selecione Create new WebLogic domain e clique em Next. Marque os seguintes produtos:

  • Oracle Universal Records Management Server
  • Oracle Information Rights Management
  • Oracle Universal Content Management – Inbound Refinery
  • Oracle Universal Content Management – Content Server
  • Oracle Imaging and Process Management

 

Fusion Middleware Configuration Wizard-5

Fusion Middleware Configuration Wizard-5

Clique em Next. Informe o nome do domínio, se quiser alter a localização e caminho das aplicações e clique em Next. Informe o usuário administrativo e senha e clique em Next. Selecione Development Mode (no nosso caso), escolha a JDK e clique em Next.  Informe os dados de conexão com o banco criado anteriormente com o RCU e clique em Next.

Fusion Middleware Configuration Wizard-6

Fusion Middleware Configuration Wizard-6

Verifique se foi tudo bem sucedido e clique em Next. Clique em Next se não tiver nenhuma configuração adicional a ser feita. Clique em Create para criar o domínio. Clique em Done para finalizar.

Agora é necessário configurar os parâmetros de inicialização dos managed servers. Inicie o admin server:

./$DOMAIN_HOME/startWeblogic.sh

Aguarde o domínio iniciar e acesse o console: http://localhost:7001/console

Efetue o login e clique em Environment, Servers, faça o seguinte para cada servidor. Selecione ele, clique em Server Start. Na caixa Arguments, se a sua JVM for Sun, informe o seguinte:

-Xms256m -Xmx1024m -XX:CompileThreshold=8000 -XX:PermSize=128m -XX:MaxPermSize=512m

Se for JRockit:

-Xms256m -Xmx1024m -XnoOpt

Clique em Save.

Vamos subir o Oracle IBR utilizando o console, caso prefira pode subir via linha de comando. Habilite o NodeManager caso já não tenha feito:

./$MIDDLEWARE_HOME/oracle_common/common/bin/setNMProps.sh

Inicie o Node Manager:

./$MIDDLEWARE_HOME/wlserver_10.3/server/bin/startNodeManager.sh &

Vá em Environment, Machines, clique em New para criar uma nova Machine. Dê um nome e clique em Finish. Se você configurou os domínios em máquinas diferentes, crie uma Machine pra cada uma e configure adequadamente. Vá em Environment, Servers. Selecione cada Server, associe cada Machine e clique em Save.

Acesse o console do domínio, vá em Environment, Servers, Control, marque o IBR_server1 clique em Start. Após iniciar acesse o IBR (Inbound Refinery). Aqui na minha máquina é o seguinte endereço: http://localhost:16250/ibr/

Verifique as configurações e altere se necessário. Mais informações sobre os parâmetros, consulte o seguinte site: http://download.oracle.com/docs/cd/E17904_01/doc.1111/e14495/configibr.htm#INECM1225. Clique em Submit. Reinicie o servidor do IBR seguindo o mesmo procedimento para Iniciar, mas executando o Shutdown e depois o Iniciar.

Para utilizar o Oracle I/PM, Oracle IBR ou o Oracle UCM Dynamic Converter é necessário configurar as fontes TrueType. Faça o procedimento descrito aqui. Acesse novamente o ibr, faça o login. Dessa vez você deverá ter o seguinte alerta:

The location of available fonts has not been set. You must set font path on the General OutsideIn Filter Options page. The font directory is used to generate font images when creating thumbnails and direct conversions to PDF. For more information, see the documentation.

Selecione Convert Settings, Third-Party Application Settings, General OutsideIn Filter Options. Clique em Options. Informe o caminho das fontes, no meu caso: “/usr/share/fonts/truetype/msttcorefonts”. Clique em Update. O alerta deverá sumir.

Alguns utilitários podem utilizar o libstdc++5. Instale com o comando:

sudo apt-get install libstdc++5

Agora é necessário realizar as configurações após instalação. Inicie todos os managed servers (ou inicie cada um a medida que for necessário). Acesse o Content Server e faça o login. Abrirá tela de configuração. Edite para os parâmetros desejados, no meu caso utilizarei FullText Search Option com a opção Internal que irá utilizar o OracleTextSearch do banco de dados. Para mais informações dos parâmetros de configuração, consulte essa documentação: http://download.oracle.com/docs/cd/E17904_01/doc.1111/e14495/configucm.htm#INECM1147. Os valores poderão ser alterados posteriormente modificando o arquivo $DOMAIN_HOME/ucm/cs/config/config.cfg e reiniciando o server. Clique em Submit. Reinicie esse servidor.

Acesse o Oracle I/PM (Imaging and Process Management) pelo seguinte endereço: http://localhost:16000/imaging. Caso você obtenha 404 (Not Found), verifique se o deploy foi feito corretamente pelo console e consulte o log do managed server: $DOMAIN_HOME/servers/IPM_server1/logs/IPM_server1.out. No meu caso o CRC do EAR estava corrompido. Se esse for o seu caso, siga as instruções descritas nesse post.

Após acessar, efetue o login. O primeiro usuário que acessar a aplicação terá acesso completo. Essas permissões poderão ser alteradas posteriormente. O próximo passo é criar uma conexão com o Content Server para que o Oracle I/PM possa conversar com o UCM. Acesse Manage Conections e no ícone da lateral direita da barra selecione Create Content Server Connection. Informe um nome e clique em Next. Selecione Use Local Content Server se a instalação foi feita na mesma máquina, caso contrário adicione um elemento no Content Server Pool especificando a localização do Content Server. Clique em Next. Adicione os usuários que terão acesso e clique em Next. Revise e clique em Submit.

Oracle Imaging and Process Management

Oracle Imaging and Process Management

A próxima etapa é configurar o GDFontPath MBean para que ele ache as fontes TrueType e possa ser feita as conversões corretamente. Acesse o Enterprise Manager: http://localhost:7001/em e faça o login. Expanda o nó Application Deployments e selecione imaging (IPM_server1). No menu Application Deployment selecione System MBean Browser. Expanda o nó Application Defined MBeans, oracle.imaging. Expanda os nós Server: IPM_server1 e config. Clique em config. Especifique o caminho das fontes TrueType (o mesmo feito anteriormente) no atributo GDFontPath, clique em Apply e reinicie o Oracle I/PM.

System MBean Browser - Oracle Enterprise Manager (weblogic)

System MBean Browser - Oracle Enterprise Manager (weblogic)

Oracle I/PM configurado. Vamos configurar o Oracle Information Rights Management (Oracle IRM). Acesse o Enterprise Manager, expanda Content Management e Information Rights Management e clique em IRM. No menu IRM, selecione Administration e General Settings. Informe a URL do servidor terminando em irm_desktop. Essa URL será utilizada na assinatura de cada documento. Portanto, após assinar um documento é expressamente não recomendado a alteração dessa URL. Clique em Apply.

General Settings - Oracle Enterprise Manager

General Settings - Oracle Enterprise Manager

Crie um Key Store seguindo os procedimentos descritos aqui. Copie o arquivo gerado para a pasta “$DOMAIN_HOME/config/fmwconfig”.

Acesse o Enterprise Manager. Expanda o Content Management e o Information Rights Management. Clique no IRM. No menu IRM, selecione Administration e General Settings. Informe o caminho completo do JKS ($DOMAIN_HOME/config/fmwconfig) na seção Keystore Settings, Path. Clique em Apply.

A próxima etapa é adicionar as senhas do keystore no credential store. Para essa etapa, acesse o WSLT:

./$MW_HOME/oracle_common/common/bin/wlst.sh

Digite o seguinte:

connect('weblogic','weblogic1','t3://localhost:7001')
createCred("IRM","keystore:irm.jks","qualquercoisa","password")
createCred("IRM","key:irm.jks:oracle.irm.wrap","qualquercoisa","password")

Onde weblogic e weblogic1 é o seu usuário e senha administrativo. Como o keystore não armazena o nome do usuário, você pode colocar qualquer coisa no parametro qualquercoisa e o password é a senha do keystore.

— Conteúdo a ser revisto

Iremos agora configurar o one-way SSL para ambiente de desenvolvimento. Execute o script para setar as variáveis de ambiente. Verifique que existe um ponto (.) antes. Isso é importante para setar as variáveis de ambiente para o shell corrente.

. ./$MW_HOME/wlserver_10.3/server/bin/setWLSEnv.sh

Utilize o CertGen para gerar a chave privada e o certificado. Substitua a senhaDaChave pela senha da chave  e hostname pelo hostname da máquina.

java utils.CertGen -selfsigned -certfile MyOwnSelfCA.cer -keyfile MyOwnSelfKey.key -keyfilepass senhaDaChave -cn "hostname"

Você deverá ter a seguinte saída: “Generating a self signed certificate with common name hostname and key strength 1024″.

java utils.ImportPrivateKey -keystore MyOwnIdentityStore.jks -storepass identitypass -keypass keypassword -alias trustself -certfile MyOwnSelfCA.cer.pem -keyfile MyOwnSelfKey.key.pem -keyfilepass mykeypass

— Fim do conteúdo a ser revisto

Agora é hora de configurar o Oracle URM. Acesse o endereço: “http://localhost:16300/urm”. Verifique as configurações e clique em Submit. Reinicie o servidor. Acesse novamente e faça o login. Um alerta irá aparecer: “Initial Records Management setup is not complete!”. Clique no link do alerta. Faça as configurações pendentes.  Verifique cada item e faça as devidas alterações. Marque todos os campos de seleção após verificar cada um deles e clique em Submit quando terminar.  Reinicie o servidor e sigas as instruções em tela. Para mais informações consulte o link: http://download.oracle.com/docs/cd/E17904_01/doc.1111/e14538/qiecm.htm#BJCCEAGH.

Feito!

Maiores informações em: http://download.oracle.com/docs/cd/E17904_01/doc.1111/e14538/qiecm.htm#BJCCEAGH

Para utilizar verifique o link: http://download.oracle.com/docs/cd/E17904_01/doc.1111/e10797/toc.htm

Criando Key Store no WebLogic

Um keystore é um repositório de certificados, normalmente utilizado para criptografia SSL. No WebLogic server a extensão desse arquivo é jks. Para manipular um keystore utilizamos a ferramenta keytool.

Execute o utilitário keytool. No meu caso, como estou configurando o Oracle IRM, o alias tem nome “oracle.irm.wrap” e o keystore “irm.jks”. Você pode alterar o tipo de algoritmo (estou utilizando RSA) e o tamanho da chave (2048). Consulte as opções na documentação do keytool. Mude de acordo com sua necessidade.

keytool -genkeypair -alias oracle.irm.wrap -keyalg RSA -keysize 2048 -keystore irm.jks

Informe a senha e o que ele for perguntando. Como estou utilizando para testes, informei tudo o default (Unknown). Pronto Key Store gerado, agora você pode utilizar o JKS criado onde ele for necessário :) .

Correção para Bug no Oracle I/PM

Fiz a instalação do Oracle ECM no Linux e um dos seus componentes o Oracle I/PM estava com defeito. O arquivo imaging-ui.war dentro do imaging.ear estava corrompido e com CRC inválido por algum motivo que eu desconheço. O erro no console foi o seguinte:

weblogic.management.DeploymentException: invalid entry CRC (expected 0x4aecad02 but got 0xf805ccae)
 at weblogic.application.internal.EarDeploymentFactory.findOrCreateComponentMBeans(EarDeploymentFactory.java:193)
 at weblogic.application.internal.MBeanFactoryImpl.findOrCreateComponentMBeans(MBeanFactoryImpl.java:48)
 at weblogic.application.internal.MBeanFactoryImpl.createComponentMBeans(MBeanFactoryImpl.java:110)
 at weblogic.application.internal.MBeanFactoryImpl.initializeMBeans(MBeanFactoryImpl.java:76)
 at weblogic.management.deploy.internal.MBeanConverter.createApplicationMBean(MBeanConverter.java:89)
 Truncated. see log file for complete stacktrace
Caused By: java.util.zip.ZipException: invalid entry CRC (expected 0x4aecad02 but got 0xf805ccae)
 at java.util.zip.ZipInputStream.readEnd(ZipInputStream.java:396)
 at java.util.zip.ZipInputStream.read(ZipInputStream.java:156)
 at java.util.zip.ZipInputStream.closeEntry(ZipInputStream.java:100)
 at java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:78)
 at weblogic.application.internal.WebServiceUtils.isWebService(WebServiceUtils.java:273)
 Truncated. see log file for complete stacktrace
>
<Apr 6, 2011 7:05:51 PM BRT> <Error> <Deployer> <BEA-149205> <Failed to initialize the application 'imaging' due to error weblogic.management.DeploymentException: invalid entry CRC (expected 0x4aecad02 but got 0xf805ccae).
weblogic.management.DeploymentException: invalid entry CRC (expected 0x4aecad02 but got 0xf805ccae)
 at weblogic.application.internal.EarDeploymentFactory.findOrCreateComponentMBeans(EarDeploymentFactory.java:193)
 at weblogic.application.internal.MBeanFactoryImpl.findOrCreateComponentMBeans(MBeanFactoryImpl.java:48)
 at weblogic.application.internal.MBeanFactoryImpl.createComponentMBeans(MBeanFactoryImpl.java:110)
 at weblogic.application.internal.MBeanFactoryImpl.initializeMBeans(MBeanFactoryImpl.java:76)
 at weblogic.management.deploy.internal.MBeanConverter.createApplicationMBean(MBeanConverter.java:89)
 Truncated. see log file for complete stacktrace
Caused By: java.util.zip.ZipException: invalid entry CRC (expected 0x4aecad02 but got 0xf805ccae)
 at java.util.zip.ZipInputStream.readEnd(ZipInputStream.java:396)
 at java.util.zip.ZipInputStream.read(ZipInputStream.java:156)
 at java.util.zip.ZipInputStream.closeEntry(ZipInputStream.java:100)
 at java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:78)
 at weblogic.application.internal.WebServiceUtils.isWebService(WebServiceUtils.java:273)
 Truncated. see log file for complete stacktrace
>

Recuperei o arquivo, descompactei e regerei o respectivo WAR. Por sorte nenhum arquivo perdido. Substitui adequadamente no EAR. Fiz um update no imaging.ear e iniciei a aplicação novamente. Acessei a aplicação e tudo funcionando adequadamente. Não sei se tive azar ou se é um bug próprio da Oracle. Caso alguém tenha o mesmo problema que eu, estou disponibilizando a versão corrigida que gerei.

Pool de conexões Siebel

Recentemente estive em um projeto e tive que desenvolver uma solução bem bacana com integração entre Oracle Webcenter e Siebel. O Siebel trabalha com tokens de segurança nas chamadas de serviços, o problema é que não há implementação de WS-Security que faça a autenticação e tokens de segurança de forma satisfatória e sem problemas. Além disso há outros detalhes de desempenho que a equipe da Siebel disse que é fundamental.

A equipe Siebel queria que fosse associada a sessão Web do usuário com a sessão de conexão com o Siebel para as chamadas de serviços. O problema dessa solução é justamente fazer essa associação de maneira correta (uma não tem nada a ver com a outra) e tratar solicitações paralelas. Isso é fundamental em ambientes Web. Outro problema é que haveriam muitas sessões Siebel ociosas, pois após o usuário realizar a requisição, ele fica analisando os dados e navegando na página, antes de realizar novas requisições. A solução que eu sugeri foi a implementação de um pool de conexões  compartilhadas com o Siebel, da mesma maneira que utilizamos para Banco de Dados. Para atender o requisito solicitado pela equipe Siebel, definimos o número de conexões mínimas igual a 1 e o máximo igual ao número de usuários conectados.

Antes de entender o funcionamento do pool Siebel, vamos entender o funcionamento dos tokens no Siebel.

Requisição anônima sem sessão

Essa foi nossa primeira abordagem antes de criar o pool de conexões. No header da requisição SOAP não enviamos nenhuma informação de usuário, apenas definimos o SessionType como None. Para cada requisição ele abre uma sessão e fecha ao enviar a resposta. O problema dessa implementação é que embora seja simples, o tempo de criação de sessão sem o uso do token é bem elevado.

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
 <SessionType xmlns="http://siebel.com/webservices">None</SessionType>
</soap:Header>
<soap:Body>
 <!-- ... -->
</soap:Body>
</soap:Envelope>

Autorização Siebel, sem sessão

Semelhante à anterior, inclusive com os mesmo problemas, mas passando o usuário e senha para autorização.

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
 <UsernameToken xmlns="http://siebel.com/webservices">usuario</UsernameToken>
 <PasswordText xmlns="http://siebel.com/webservices">senha</PasswordText>
 <SessionType xmlns="http://siebel.com/webservices">None</SessionType>
</soap:Header>
<soap:Body>
 <!-- ... -->
</soap:Body>
</soap:Envelope>

Autorização Siebel com sessão stateless

Essa foi a solução adotada para o pool de conexões com o Siebel que explicarei mais adiante. O funcionamento é simples de entender, mas um pouco trabalhoso de se implementar já que é sempre necessário guardar o último token de cada conexão. A primeira requisição deve realizar a autorização passando o usuário, senha e o tipo de sessão Stateless, com isso uma sessão é aberta para esse usuário. Ao obter uma resposta da requisição, o Siebel retornará o token de segurança que deverá ser utilizado na próxima requisição, que retornará outro token de segurança que deverá ser utilizado na próxima requisição e assim por diante. Para finalizar a sessão Siebel é só passar o usuário e senha com o tipo de sessão None.

Requisição inicial

Para efetuar o log in e criar a sessão é necessário passar o seguinte header:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
 <UsernameToken xmlns="http://siebel.com/webservices">usuario</UsernameToken>
 <PasswordText xmlns="http://siebel.com/webservices">senha</PasswordText>
 <SessionType xmlns="http://siebel.com/webservices">Stateless</SessionType>
</soap:Header>
<soap:Body>
 <!-- ... -->
</soap:Body>
</soap:Envelope>

Dessa forma ele deverá retornar uma resposta parecida com essa:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
 <siebel-header:SessionToken xmlns:siebel-header="http://siebel.com/webservices">TokenCriptografadoComValorEstranhoDoResponse
</siebel-header:SessionToken>
</soap:Header>
<soap:Body>
 <!-- ... -->
</soap:Body>
</soap:Envelope>

Próximas Requisições

Para as próximas requisições e necessário recuperar o token da resposta e colocar no header da requisição da seguinte forma:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<SessionType xmlns="http://siebel.com/webservices">Stateless</SessionType>
<SessionToken xmlns="http://siebel.com/webservices">TokenCriptografadoComValorEstranhoDoResponse</SessionToken>
</soap:Header>
<soap:Body>
<!-- ... -->
</soap:Body>
</soap:Envelope>

E assim por diante. Existe a opção do tipo de sessão ser Statefull também para manter o estado da sessão. O funcionamento é o mesmo, só muda o SessionType para Statefull.

Pool de conexões

Como assinei contrato de confidencialidade não poderei disponibilizar o código fonte utilizado no projeto, mas explicarei os caminhos necessários para tudo funcionar adequadamente.

Para a inclusão do header nas requisições do Siebel, utilizei um SOAPHandler. O SOAPHandler funciona como uma espécie de “filtro” para todas as requisições que utilize ele. Dessa forma eu posso modificar o header, alterar a requisição e obter ou mesmo alterar os dados da resposta. Para realizar isso, é só criar uma classe que implemente a interface SOAPHandler como no exemplo e associar com os clientes de cada serviço (JAX-WS 2.0).

public class SiebelHandler implements SOAPHandler<SOAPMessageContext> {
    //...
}

Dos métodos que a interface nos obriga a implementar utilizaremos dois: handleMessage e handleFault. Que é onde iremos modificar os headers e obter os tokens.

    public boolean handleMessage(SOAPMessageContext smc) {
        Boolean outboundProperty =
            (Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (outboundProperty.booleanValue()) {
            SiebelTokenHelper tokenHelper =
                SiebelSimpleTokenManager.getInstance().getNextToken();
            tokenUsed(tokenHelper);
            SOAPMessage message = smc.getMessage();
            try {
                SOAPEnvelope envelope =
                    smc.getMessage().getSOAPPart().getEnvelope();
                SOAPHeader header = envelope.getHeader();
                if (header == null) {
                    header = envelope.addHeader();
                }
                // Token
                if (tokenHelper.getTokenValue() == null) {
                    SOAPElement userNameToken =
                        header.addChildElement("UsernameToken", "",
                                               "http://siebel.com/webservices");
                    userNameToken.addTextNode(tokenHelper.getUser());
                    SOAPElement password =
                        header.addChildElement("PasswordText", "",
                                               "http://siebel.com/webservices");
                    password.addTextNode(tokenHelper.getPassword());
                } else {
                    SOAPElement sessionToken =
                        header.addChildElement("SessionToken", "",
                                               "http://siebel.com/webservices");
                    sessionToken.addTextNode(tokenHelper.getTokenValue());
                }
                SOAPElement sessionType =
                    header.addChildElement("SessionType", "",
                                           "http://siebel.com/webservices");
                if (isLogout(envelope)) {
                    sessionType.addTextNode("None");
                    SiebelSimpleTokenManager.getInstance().removeFromPool(tokenHelper);
                    tokenHelper = null;
                } else {
                    sessionType.addTextNode("Stateless");
                }
            } catch (Exception e) {
                logger.log(Level.SEVERE, "Erro ao invocar servico", e);
            }
        } else {
            SiebelTokenHelper tokenHelper = getUsedToken();
            try {
                SOAPMessage message = smc.getMessage();
                if (tokenHelper != null) {
                    Node tokenCHild = message.getSOAPHeader().getFirstChild();
                    if (tokenCHild != null) {
                        tokenHelper.setTokenValue(tokenCHild.getTextContent());
                    }
                }
            } catch (Exception ex) {
                ex.printStackTrace();
                tokenHelper.setTokenValue(null);
            } finally {
                if (tokenHelper != null) {
                    SiebelSimpleTokenManager.getInstance().pushElemIntoPool(tokenHelper);
                }
            }
        }
        return outboundProperty;
    }

A primeira condição na linha 05 verifica se é requisição ou reposta. Se for requisição o valor será verdadeiro. Na linha 07 e 08 utilizo uma implementação de fila (utilizando LinkedList) para recuperar o elemento mais antigo (menos recente usado), removo ele da fila para que outras conexões Siebel possam ser utilizadas, ele será novamente inserido no final da fila (linha 74), após ter o valor do token atualizado (linha 65) na resposta (linha 57). Na linha 22 verifico se existe token anterior ou se é uma conexão nova. Se for uma conexão nova, atribuo o valor do usuário (linha 26), da senha (linha 31). Caso contrário, utilizo o token (linha 38) atributo anteriomente na resposta (linha 65). Se for uma requisição de logout (linha 45), atribuo o SessionType como None, caso contrário Stateless.

O coração da implementação é esse método, mas ainda não estamos tratando exceção e reestabelecendo a conexão caso a sessão expire. Para reestabelecer a conexão, basta colocar no catch do cliente uma nova tentativa se o erro tiver o código 10944642. No nosso handleFault basta remover da fila para não ser mais utilizado, caso contrário, se for outro tipo de erro, o token é retornado no fault e devemos atribuir para ser utilizado na próxima requisição. Quando a sessão expira o Siebel retorna a seguinte mensagem:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <SOAP-ENV:Body>
 <SOAP-ENV:Fault>
 <faultcode>SOAP-ENV:Client</faultcode>
 <faultstring>Error Code: 10944642 Error Message: Error: Inbound SOAP Message - Session Token is missing or invalid or has expired</faultstring>
 <detail>
 <siebelf:errorstack xmlns:siebelf="http://www.siebel.com/ws/fault">
 <siebelf:error>
 <siebelf:errorsymbol/>
 <siebelf:errormsg>Error: Inbound SOAP Message - Session Token is missing or invalid or has expired</siebelf:errormsg>
 </siebelf:error>
 </siebelf:errorstack>
 </detail>
 </SOAP-ENV:Fault>
 </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Por isso devemos tratar quando obtermos o código: 10944642, pois não é um erro de serviço, é somente sessão expirada. O controle de criação de novas conexões foi feito em uma classe que possui a fila de conexões e tokens e o controle do número máximo foi feito utilizando um Managed Bean para contabilização de login e logout e um Session Listener, para caso o usuário esqueça de clicar no botão Sair.

Para testar a Oracle disponibiliza um VM do Siebel no e-delivery. Com essa implementação, tivemos um ganho de performance absurdo, paralelizamos as requisições e otimizamos o uso de sessões e compartilhamento de tokens no Siebel.

Criação de JAR para clients WebLogic

Em aplicações clients de serviços fornecidos pelo Oracle WebLogic Server é necessária a inclusão no classpath de uma JAR com as classes que serão utilizadas para acessar o Weblogic. Esse JAR pode ser gerado utilizando uma ferramenta que vem no próprio WebLogic.

Para essa tarefa é só acessar a pasta server/lib do WebLogic Server e digitar o seguinte comando:

java -jar wljarbuilder.jar

No console deverá aparecer o seguinte:

Creating new jar file: wlfullclient.jar
...
Created new jar file: /development/Oracle11114/Middleware/wlserver_10.3/server/lib/wlfullclient.jar

Aí é só utilizar as classes disponíveis no JAR em sua aplicação. Mais informações podem ser encontradas aqui: http://download.oracle.com/docs/cd/E12840_01/wls/docs103/client/jarbuilder.html

Wrapper/Adapter Serializable

Para gravarmos dados na sessão do usuário é necessário que as classes implementem a interface java.io.Serializable. Caso isso não ocorra, podemos ter erro com a exceção: NotSerializableException ou mal funcionamento da aplicação, principalmente se você estiver em ambiente clusterizado com replicação de sessão.

E isso se torna, um problema quando trabalhamos com a geração automática de clientes de Web Services, pois as classes são geradas sem “implements java.io.Serializable”. Portanto não podemos inserir essas classes no contexto de sessão. Uma solução é editar as classes geradas incluindo o “implements java.io.Serializable”. O problema dessa abordagem é que ao gerar novamente as classes (como por exemplo: alteração de endpoint, atualização de WSDL ou inclusão de política de segurança ou SOAP Handler), as classes com “implements java.io.Serializable” serão sobreescritas e essa solução perderá validade, sendo necessário alterar todas as classes novamente.

Uma boa alternativa para resolver esse problema é a criação de Wrappers serializáveis para classes não serializáveis. Com base nesse problema resolvi criar uma interaface auxiliar para obrigar a implementação da conversão entre o Wrapper e a classe alvo.

public interface Wrappable extends Serializable {
   public void wrap(T objectToCopy);
   public T unwrap();
}

O método wrap é responsável por receber um objeto e copiar os atributos necessários e o unwrap reconstrói o objeto. Para fins de demonstração utilizaremos a seguinte classe:

public class Boo {
   private String doo;
   private int foo;
   public Boo(String doo, int foo) {
      super();
      this.doo = doo;
      this.foo = foo;
   }
   public String getDoo() {
      return doo;
   }
   public void setDoo(String doo) {
      this.doo = doo;
   }
   public int getFoo() {
      return foo;
   }
   public void setFoo(int foo) {
      this.foo = foo;
   }
}

Essa é uma classe não serializável. Para criar o Wrapper serializável correspondente é só implementar devidamente a interface:

public class BooWrapper implements Wrappable {
   private static final long serialVersionUID = 201103151148L;
   private String doo;
   private int foo;
   public BooWrapper(Boo object) {
      wrap(object);
   }
   @Override
   public void wrap(Boo objectToCopy) {
      this.doo = objectToCopy.getDoo();
      this.foo = objectToCopy.getFoo();
   }
   @Override
   public Boo unwrap() {
      return new Boo(doo, foo);
   }
}

Não é recomendado herdar a classe ou mesmo incluí-la como atributo pois como ela não é serializável e também pode conter atributos não serializáveis, o problema não será resolvido (se mesmo assim você quiser, pode marcá-la como transiente). Com base no exemplo acima, podemos utilizar o Wrapper como um Adapter e alterar nome dos atributos/métodos, inserir métodos auxiliares e inserir somente o necessário na sessão. Diminuindo o acoplamento entre a camada Web e a camada de serviços.

Uma outra possibilidade é criar um arquivo de personalização dos bindings do JAXB para ter suporte à Serializable: http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.6/jaxb/vendorCustomizations.html#serializable

« Página AnteriorPróxima Página »