domingo, 29 de abril de 2012

Desfragmentando automaticamente o HD de um servidor Siebel

Bem, se você chegou até aqui é porque passou do título do artigo e não pensou "caramba, eu gerencio um servidor Siebel em um sistema operacional com sistema de arquivos decente, eu não preciso saber disto".

Ainda por aqui? Bem, então é porque provavelmente tem um servidor Siebel instalado em alguma versão do Microsoft Windows Server e com unidades de disco em estado deprimente de fragmentação porque ninguém se lembra de fazer isto, principalmente se o servidor em questão é utilizado para desenvolvimento ou QA.

Já faz algum tempo que eu resolvi (meio que por falta de opção, para dizer a verdade) fazer automações com Windows Powershell e descobri como automatizar a desfragmentação de um servidor Siebel sem nenhuma intervenção manual.

Para fazer isto, eu usei o programa defrag.exe que está disponível por padrão na instalação do Windows e algum código em Powershell 2 para parar os serviços do Siebel e reiniciá-los quando defrag.exe acabar seu trabalho. De quebra, o script ainda gera um arquivo de registro rudimentar para revisão.

Segue o código abaixo para fazer isto:

set-strictmode -version 2.0

# a ordem aqui é importante: parar o IIS, parar o serviço do servidor Siebel e
# parar o serviço do SiebelG Gateway
$services = @('W3SVC','siebsrvr_SIEBEL_foobar','gtwyns')
$timeToWait = 180
$now = get-date
$logFile = 'results-' + $now.Day.ToString() + $now.Month.ToString() + $now.Year.ToString() + '.txt'

'[' + $now.ToString() + '] Starting management of disks' | Out-File $logFile

try {

    foreach ($serviceName in $services) {

        "Stopping $serviceName service" | Out-File -Append $logFile
       
        $service = Stop-Service $serviceName -PassThru -Force
       
        if ( $service -ne $null ) {
           
            if ( $service.Status -ne 'Stopped' ) {
           
                throw "Could not stop $serviceName. Aborting..."
           
            } else {
           
                "$serviceName was stopped successfully" | Out-File -Append $logFile
           
            }
           
        }
       
    }
   
    "Defragmenting drives" | Out-File -Append $logFile
    "Defragmenting drive C:" | Out-File -Append $logFile
    defrag c: -v 2>&1 | Out-File -Append $logFile
    "Defragmenting drive D:" | Out-File -Append $logFile
    defrag d: -v 2>&1 | Out-File -Append $logFile
   
    [array]::Reverse($services)
   
    foreach ($serviceName in $services) {

        "Starting $serviceName service" | Out-File -Append $logFile
       
        $service = Start-Service $serviceName -PassThru
       
        if ( $service -ne $null ) {
       
            if ( $service.Status -ne 'Running' ) {
           
                throw "Could not start $serviceName. Aborting..."
           
            } else {
           
                "$serviceName was started successfully" | Out-File -Append $logFile
           
            }
       
        }
       
        "Waiting $timeToWait seconds to give time to the process start correctly" | Out-File -Append $logFile
       
        Start-Sleep -Seconds $timeToWait
       
    }   
   
} catch {

    $error[0].exception | Out-File -Append $logFile


} finally {


}

Partes interessantes para comentar do código:
  • Procure o nome dos serviços em Computer Management, Services and Application, Services (pelo menos este é um dos caminhos no Windows Server 2003, pode variar em outras versões).
  • Depois que os serviços são parados, o array é invertido para que os serviços sejam iniciados novamente na ordem correta.
  • Repare que as mensagens de saída padrão e erro padrão do defrag.exe são redirecionadas para o arquivo de log com um "2>&1" (ideia vergonhosamente copiada do que existe na maioria dos shell scritps de sistemas UNIX-like). Existem formas mais elegantes (e trabalhosas) para fazer isto com as classes System.Diagnostics.ProcessStartInfo e System.Diagnostics.Process, mas você vai ter que aprender um pouco de .Net para usá-las.
  • No caso, o script realiza a desfragmentação nas unidades C:\ e D:\ do servidor, talvez você tenha uma combinação diferente.
  • O script espera um tempinho para dar tempo dos serviços serem iniciados corretamente. O tempo necessário para isto pode variar bastante.
  • Não é que eu esqueci de colocar algo interessante dentro do block finally, eu simplesmente não achei nada interessante para fazer ali.
Depois disso, é só agendar a tarefa para executar em algum horário interessante e partir para o abraço.


Se você gosta de emoções fortes, pode até fazer isto em ambiente de produção, mas eu não faria isto se fosse você: esse tipo de coisa tem que ser bem programada e acompanhada de perto.

Este script Powershell, assim como outros, é parte do projeto de código aberto Siebel GNU Tools. O website do projeto está localizado em https://code.google.com/p/siebel-gnu-tools/.

terça-feira, 17 de abril de 2012

Com que livro eu vou?

Pode parecer piada, mas conheço muitos profissionais de informática que não leem livros da área. Já escutei até um "ler esses livros é coisa de nerd". Ahn?!?

Dizer isso não tem muito sentido, exceto talvez para aqueles que tem recursos financeiros suficientes para pagar (com frequência) um treinamento com instrutor ou psicografar o conhecimento de profissionais já desencarnados...

Eu considero que ler material técnico é uma das melhores formas de se manter atualizado ou aprender coisas novas. Com computadores pessoais (tendo capacidade de processamento considerável) e banda larga com custos acessíveis, estudar em casa através de um livro é uma boa alternativa para muitos campos da informática. O mesmo se aplica a revistas periódicas da área.

Outro argumento que escuto bastante é "tem na internet". É, realmente tem. O problema é que escrever material técnico de qualidade dá trabalho e a diferença em ler algo de qualidade boa ou ruim é que o primeiro te faz ganhar tempo ao evitar que você fique batendo cabeça por falta de informações e/ou informações incorretas.

Talvez seja por isso que o mercado editorial para a área não seja tão bom quanto poderia ser. Geralmente ficamos com as opções de ler material traduzido (e só por ser traduzido, em geral, já está desatualizado) ou livros mal editados ou com conteúdo técnico exclusivamente introdutório.

Não estou dizendo com isso que não temos obras boas: as editoras Brasport e Novatec tem feito um bom trabalho com material 100% brasileiro. E eu considero os trabalhos da editora Bookman realmente fantásticos, tanto na tradução quanto editoração e acabamento.

Mas como saber qual livro comprar? Opções existem aos montes.

Ao contrário de websites como a Amazon que possuem resenhas e notas de livros consistentes (você não vê somente elogios e as resenhas não "caducam" com o tempo) eu não tenho visto nada parecido no Brasil. Eu mesmo já publiquei resenhas em websites famosos de compras e a resenha nunca apareceu ou depois de algum tempo tomou um "chá de sumiço".

Há algum tempo atrás me apresentaram o website Skoob, que nada mais é que uma rede social exclusiva para livros. Ali é possível, ao menos, obter a nota dada por leitores de diversos livros da área de informática, isso quando não for possível ler uma resenha ou outra por aí (algo que espero que mude com o amadurecimento da rede).

Eu mesmo já arrisquei algumas resenhas por lá. Você pode vê-las em http://www.skoob.com.br/estante/resenhas/310422.

Estou com os dedos cruzados esperando que a rede no Skoob amadureça cada vez mais, afinal é uma forma independente de darmos um "empurrãozinho" no mercado editoral brasileiro para termos obras melhores e mais completas!

sábado, 31 de março de 2012

Trabalhando com arquivos no eScript

O Siebel possui sua própria linguagem script para programação: o eScript.
De acordo com as boas práticas só se programa em eScript quando não existem outras opções para aplicar a lógica de negócios no sistema (por conta de facilidade de realizar atualizações de versão no Siebel). Isso inclui, não raramente, a necessidade de ler ou escrever arquivos no sistema de arquivos aonde o servidor Siebel está instalado (ou no sistema de arquivos do Siebel Client, mas não vou falar de Browser Scripting neste artigo).
Para manipulação de arquivos o eScript oferece a biblioteca Clib: esta biblioteca oferece funções muito parecidas com aquelas existentes na linguagem ANSI C. Não vou repetir aqui o que já se encontra documentado no respectivo Siebel Bookshelf (Siebel eScript Language Reference) mas sim citar alguns macetes aprendidos depois de quebrando a cabeça por aí.

Teste o diretório antes de usá-lo


Antes de usar um diretório é sempre uma boa idéia verificar se o script tem acesso a ele (principalmente se a versão do Siebel que você está trabalhando não tem a função Clib.strerror trabalhando corretamente). Uma forma simples de testar isto é utilizar as funções Clib.chdir e Clib.getcwd em combinação, como mostrado na função testDir definida abaixo:

function testDir(dir)
{
    try
    {
        //tests if the directory is valid
        var previousDir = Clib.getcwd();
        var testResult = -1;
       
        testResult = Clib.chdir( dir );
       
        if ( testResult == -1 )
        {
            TheApplication().RaiseErrorText('The directory ' + dir + ' does not exists or cannot be accessed.');
        }
    }
    catch(e)
    {
        TheApplication().RaiseErrorText('Error in function testDir: ' + e.toString());
    }
}


Isso vai ajudar você a identificar erros de permissão (ou não existência) do diretório antes de tentar usá-lo.

Teste se o arquivo foi aberto

Parece besteira, mas às vezes acho alguns programas por aí que simplesmente não fazem um teste depois que abrem um arquivo com Clib.fopen. É muito simples fazer isto, como mostrado abaixo:

    fp = Clib.fopen(myFile,"au");

    if ( fp == null )
    {
        TheApplication().RaiseErrorText('An error ocurrered when trying to open ' + myFile);
    }


Com três linhas de código você evitará ter que fazer debugging por conta de erro nas permissões no sistema de arquivo, por exemplo. Por que isso? Porque esses erros não são considerados falhas graves: a Clib irá falhar silenciosamente...
A propósito, as funções Clib.fputs e Clib.fclose seguem o mesmo raciocínio, retornando null no caso de terem problemas. Se você estiver se sentido particularmente paranoico também pode incluir os mesmos tipos de testes.

Favoreça o uso do buffer

As funções de leitura e escrita da Clib utilizam buffer por padrão: isso quer dizer que elas guardam em memória os dados antes de realizar uma operação de E/S. Isso favorece o desempenho do seu programa porque operações de E/S em disco são mais lentas do que em memória (não estou nem considerando o cache do disco). Se você fizer isto dentro do mesmo escopo:

    fp = Clib.fopen(myFile,"au");

    if ( fp == null )
    {
        TheApplication().RaiseErrorText('An error ocurrered when trying to open ' + myFile);
    }
   
    Clib.fputs(myData,fp);
    Clib.fclose(fp);


você simplesmente desperdiça o buffer. Uma vez argumentaram comigo que utilizar Clib para mensagens de registro era reinventar a roda já que para este fim existe a função TheApplication().Trace. O problema desta função é que você não tem controle sobre o buffer: ela escreve imediatamente isto no disco, ou seja, abre o arquivo, escreve e imediatamente fecha o arquivo depois.
Já a Clib permite que você tenha controle sobre como o buffer se comporta e se você estiver escrevendo grandes quantidades de dados o buffer poderá te ajudar.
Para isto, basta criar uma variável (global, se você for usá-la durante o Business Service todo) e abrir o arquivo apenas uma vez com Clib.fopen. Após isto, basta seguir utilizando Clib.fputs e seus primos.
Como garantir então que o arquivo será fechado? Isso é particularmente um problema se o servidor Siebel está utilizando um sistema de arquivos com locking mandatório como o NTFS: seu arquivo ficará "preso" até que o processo que o executou explicitamente feche ele ou deixe de existir.
Para evitar este tipo de problema basta usar o bloco finally para fechar o arquivo.

# na área de declarations
    var fp;
   
function foobar {

    try {

    fp = Clib.fopen(myFile,"au");

    if ( fp == null )
    {
        TheApplication().RaiseErrorText('An error ocurrered when trying to open ' + myFile);
    }
   
    Clib.fputs(myData,fp);
   
    } catch(e) {
   
        //do something
   
    } finally {
   
        Clib.fclose(fp);
   
    }
   
}


Com isto, a menos que o processo que está executando o Business Service seja encerrado (e o locking arquivo liberado no processo) garantidamente o arquivo será fechado e quaisquer dados que ainda não tenha sido escritos o serão antes do arquivo ser fechado. Com isto você tem maiores garantidas de que os dados não foram perdidos (não totalmente pelo menos) e o locking do arquivo seja removido pelo sistema de arquivos.
Precisa que os dados sejam escritos (por maior garantia de não perder os dados) no arquivo a cada Clib.fputs? Use a Clib.fflush para este fim, sem fechar o arquivo.

Copiando arquivos

O artigo "How Can You Copy Files from One Location to Another Using Siebel Scripting?" (ID 477948.1) disponível na página de suporte da Oracle ensina algumas alternativas de como resolver isto já que a Clib, por algum motivo que eu não entendo muito bem, não tem funções específicas para esta funcionalidade tão comum.
Das alternativas que ele ensina, a melhor mesmo é utilizar Clib.rename: se você já usou alguma vez o prompt de algum SO UNIX ele se parece muito com o comando mv.
As outras alternativas (Clib.system e SElib) são "custosas" demais para fazer isto e mais complicadas de utilizar. Se for necessário copiar muitos arquivos, talvez seja interessante então criar um programa pequeno em outra linguagem de programação e então executá-lo com Clib.system, assim você executa este programa uma única vez e ele faz todo o trabalho de uma vez.

Listando arquivos em um diretório

Essa dica só é válida para instalações do Siebel em SO's da Microsoft (Windows).
O suporte da Oracle tem artigos ensinando a usar SElib e a DLL kernel32.dll para conseguir procurar por padrões de arquivos em algum diretório qualquer. Pena que o artigo só ajuda até certo ponto: já vi código por aí chamando a função FindFirstFileA do kernel32.dll recursivamente quando a função FindNextFileA está lá disponível justamente para resolver estas questões. É um processo doloroso ler a documentação (principalmente porque ela é para programadores C++, o que não é o meu caso) mas ela esta lá (http://msdn.microsoft.com/en-us/library/windows/desktop/aa364418%28v=vs.85%29.aspx) justamente para evitar este tipo de bobagem.
Outro problema é lidar com caracteres nulos: um tamanho pré-definido de memória é alocada para guardar o nome do arquivo que for encontrado: na falta de algo melhor, as funções FindFirstFileA e FindNextFileA vão preencher o que restar do tamanho alocado com caracteres nulos caso o nome do arquivo seja menor. Parece normal se você estiver programando em C ou C++, mas tente concatenar strings (ou qualquer outra coisa, como usar split) com eScript e com o resultado devolvido e você verá que as coisas não vão funcionar como esperado.
A função abaixo é uma solução possível para resolver este tipo de problema: ela irá procurar o primeiro caracter nulo na string e retornar o número de caracteres "imprimíveis" lidos até então.

function removeNul(string)
{
    try
    {
        var iEndPos = string.length;
        var lastPrintChar = 0;

        for (var i = 0; i < iEndPos; i++) {
 
            //if char is printable, go to next until test fails
            if ( Clib.isprint( string.charAt(i) ) )
            {
           
                lastPrintChar++;
           
            }
            else {
           
                break;
           
            }
       
        }
       
        return string.substring(0, lastPrintChar);
   
    }
    catch(e) {
   
        logMessage('An error ocurred with removeNul function: ' + e.errText);
   
    }

}


Abaixo eu coloquei um exemplo completo de listagem de arquivos considerando estas questões que comentei, só para ilustrar os conceitos. Repare que os resultados encontrados são guardados em um array para que o garbage collector do eScript tenha oportunidade de se livrar logo da memória alocada para os objetos e kernel32.dll.

    try {

        var blob = new blobDescriptor();
        var fileData;
        var hFind;
       
        blob.dwFileAttributes = SWORD32;
        blob.ftCreationTime = SWORD32;
        blob.ftCreationTime_ = SWORD32;
        blob.ftLastAccessTime = SWORD32;
        blob.ftLastAccessTime_ = SWORD32;
        blob.ftLastWriteTime = SWORD32;
        blob.ftLastWriteTime_ = SWORD32;
        blob.nFileSizeHigh = SWORD32;
        blob.nFileSizeLow = SWORD32;
        blob.dwReserved0 = SWORD32;
        blob.dwReserved1 = SWORD32;
        blob.cFileName = 1000000;
        blob.cAlternateFileName = 1000000;
       
        var nextIndex = filesToProcess.length;
       
        // brand new start of filesToProcess
        if (typeof nextIndex == 'undefined') {
       
            nextIndex = 0;
            filesToProcess[0] = '';
       
        }
       
        hFind = SElib.dynamicLink("Kernel32.DLL", "FindFirstFileA", STDCALL, filenameToMatch, blob, fileData);

        //foi encontrado um arquivo de acordo com o padrão informado
        if (hFind != -1) {

            filesToProcess[nextIndex] = removeNul(fileData.cFileName.toString());

            while (SElib.dynamicLink("Kernel32.DLL", "FindNextFileA", STDCALL, hFind, blob, fileData) != 0)
            {
           
             nextIndex++;
            
             filesToProcess[nextIndex] = removeNul(fileData.cFileName.toString());            
           
            }
               
            return true;
        }
    }
    catch(e) {
   
        throw(e);
       
    }
    finally {
   
        nextIndex = null;
        fileData = null;
   
    }
}


Leia e escreva em Unicode

Um dos modos disponíveis para a função Clib.fopen é de leitura e escrita em Unicode através da letra "u" especificada na chamada da Clib.fopen.
Trabalhar neste modo é a melhor garantia que você pode ter de conseguir exportar ou importar dados de forma portável entre sistemas, principalmente se o banco de dados do Siebel estiver codificado em Unicode (o que, atualmente, é bem possível). Trabalhar com Unicode vai evitar dores de cabeça futuras com acentos e outras mazelas associadas com diferentes codificações de caracteres.

quinta-feira, 1 de março de 2012

Mais alguns truques com o srvrmgr

A um tempo atrás eu havia postado um artigo (Fazendo melhor uso do srvrmgr.exe) sobre o srvrmgr mas faltou falar sobre a manipulação de saída de dados, incluindo um truquezinho sujo que não está documentado. Vamos a eles.

Manipulando a saída dos comandos

É possível alterar a forma como o srvrmgr irá exibir a saída dos programas. Por exemplo, a saída padrão do comando list comp é está aqui:

srvrmgr> list comp

SV_NAME     CC_ALIAS                       CC_NAME                                   CT_ALIAS  CG_ALIAS      CC_RUNMODE   CP_DISP_RUN_STATE  CP_NUM_RUN_  CP_MAX_TASK  CP_ACTV_MTS  CP_MAX_MTS_  CP_START
_TIME        CP_END_TIME  CP_STATUS  CC_INCARN_NO  CC_DESC_TEXT
----------  -----------------------------  ----------------------------------------  --------  ------------  -----------  -----------------  -----------  -----------  -----------  -----------  --------
-----------  -----------  ---------  ------------  ------------
siebsrvdev  BusIntBatchMgr                 Business Integration Batch Manager                  EAI           Batch        Online             0            20           1            1            2012-03-
01 14:59:11
siebsrvdev  BusIntMgr                      Business Integration Manager                        EAI           Batch        Online             0            20           1            1            2012-03-
01 14:59:11
siebsrvdev  ClientAdmin                    Client Administration                               System        Background   Online             0            1                                      2012-03-
01 14:59:11
siebsrvdev  CommConfigMgr                  Communications Configuration Manager                CommMgmt      Batch        Online             0            20           1            1            2012-03-

A saída está truncada, mas isto foi proposital: é exatamente desta forma que os dados foram exibidos no meu terminal. Se você usa isto com frequência provavelmente fica meio aborrecido com o resultado não muito agradável de ler.

Isso pode ser alterado pelo comando configure list. Vamos a ajuda online dele:

srvrmgr> help configure list
  configure list <ValidListCmd> 
       [show <column_name> [ AS <column_header>]]
       [, <column_name>    [ AS <column_header>]] ....

O comando faz exatamente isto: configura um dos subcomandos disponível para o comando list. Ele permitirá que você configure, por exemplo, quais as colunas você quer que sejam exibidas. Vamos ver como está a configuração atual para o list comp:

srvrmgr> configure list comp
    SV_NAME (31):  Server name
    CC_ALIAS (31):  Component alias
    CC_NAME (76):  Component name
    CT_ALIAS (31):  Component type alias
    CG_ALIAS (31):  Component GRoup Alias
    CC_RUNMODE (31):  Component run mode (enum)
    CP_DISP_RUN_STATE (61):  Component display run state
    CP_NUM_RUN_TASKS (11):  Current number of running tasks
    CP_MAX_TASKS (11):  Maximum tasks configured
    CP_ACTV_MTS_PROCS (11):  Active MTS control processes
    CP_MAX_MTS_PROCS (11):  Maximum MTS control processes
    CP_START_TIME (21):  Component start time
    CP_END_TIME (21):  Component end time
    CP_STATUS (251):  Component-reported status
    CC_INCARN_NO (23):  Incarnation Number
    CC_DESC_TEXT (251):  Component description

Se você incluir a opção show você poderá especificar quais as colunas você quer ver e em qual ordem elas irão ser mostradas:

srvrmgr> configure list comp show SV_NAME(31),CC_ALIAS(21),CC_NAME(76)

srvrmgr> configure list comp
        SV_NAME (31):  Server name
        CC_ALIAS (21):  Component alias
        CC_NAME (76):  Component name

srvrmgr> list comp

SV_NAME     CC_ALIAS              CC_NAME
----------  --------------------  ----------------------------------------
siebsrvdev  BusIntBatchMgr        Business Integration Batch Manager
siebsrvdev  BusIntMgr             Business Integration Manager
siebsrvdev  ClientAdmin           Client Administration
siebsrvdev  CommConfigMgr         Communications Configuration Manager
siebsrvdev  CommInboundMgr        Communications Inbound Manager
...
siebsrvdev  eSitesClinicalObjMgr  eSitesClinical Object Manager (PTB)

52 rows returned.

Agora ficou mais fácil ler!

Mas pode ser que você precise ter todas as colunas e se for o caso, o que fazer?

Aí que vem o truque sujo (até aonde eu sei) não documentado. Lhes apresento o comando set. Com ele você pode exibir ou alterar alguns parâmetros do ambiente do srvrmgr. Vamos ver as opções:

srvrmgr> set
username            sadmin*
service             (null)
enterprise          (null)
app server          (null)
compression         FALSE*
encryption          FALSE*
protocol            TCP/IP*
port                (null)*
cluster             (null)*
name server         (null)*
log filter          (null)
verbose             FALSE
batch               FALSE
header              TRUE
footer              TRUE
ColumnWidth         (null)
delimiter          

Não vou explicar aqui cada um destes parâmetros (até porque isto está documentado). A questão fica por conta do parâmetro ColumnWidth. Se você habilitar ele será possível definir o tamanho das colunas através do comando configure list.

srvrmgr> set ColumnWidth true

srvrmgr> set
username            sadmin*
service             (null)
enterprise          (null)
app server          (null)
compression         FALSE*
encryption          FALSE*
protocol            TCP/IP*
port                (null)*
cluster             (null)*
name server         (null)*
log filter          (null)
verbose             FALSE
batch               FALSE
header              TRUE
footer              TRUE
ColumnWidth         1
delimiter  

Pronto! Agora você pode definir o tamanho das colunas! Repare que no comando configure list você vê o nome da coluna e um número entre parênteses: esse número é o tamanho em caracteres da coluna. O comando abaixo de exemplo altera o tamanho de alguns campos do comando list comp para que nome das colunas não seja truncado:

srvrmgr> configure list comp show SV_NAME(31),CC_ALIAS(21),CC_NAME(76),CT_ALIAS(31),CG_ALIAS(31),CC_RUNMODE(31),CP_DISP_RUN_STATE(61),CP_NUM_RUN_TASKS(16),CP_MAX_TASKS(12),CP_ACTV_MTS_PROCS(17),CP_MAX_MTS_PROCS(16),CP_START_TIME(21),CP_END_TIME(21),CP_STATUS(251),CC_INCARN_NO(23),CC_DESC_TEXT(251)

Evitando ter que repetir este trabalho todo

Depois de configurar tantas coisas você deve ter pouca vontade de ter que digitar uma segunda vez isso tudo. para isto existe os comandos save preferences e load preferences. Esses comandos vão, respectivamente, gravar um arquivo de configuração no diretório aonde está localizado srvrmgr e depois carregá-lo. O nome do arquivo é por padrão ".Siebel_svrmgr.pref". Na realidade é um arquivo texto simples. Se depois de você fazer esta configuração você salvar o arquivo e resolver editá-lo, você verá exatamente isto:

configure list components show SV_NAME(31) , CC_ALIAS(21) , CC_NAME(76) , CT_ALIAS(31) , CG_ALIAS(31) , CC_RUNMODE(31) , CP_DISP_RUN_STATE(61) , CP_NUM_RUN_TASKS(16) , CP_MAX_TASKS(12) , CP_ACTV_MTS_PROCS(17) , CP_MAX_MTS_PROCS(16) , CP_START_TIME(21) , CP_END_TIME(21) , CP_STATUS(251) , CC_INCARN_NO(23) , CC_DESC_TEXT(251)

Realmente não é nenhuma mágica, mas funciona.

Conclusão

Talvez você esteja se perguntando para que serventia ter este trabalho todo. Bem, se você estiver escrevendo um parser dos comandos do srvrmgr (como eu estou fazendo aqui) isso é de grande valia!

Falando sério agora, ter a possibilidade de customizar o ambiente do programa para suas necessidades vai lhe ajudar bastante no seu trabalho, principalmente a ganhar agilidade para fazer as coisas. Verifique também a possibilidade de criar alias e salvá-los via save preferences, você vai ver que isso vai lhe ajudar bastante!

segunda-feira, 20 de fevereiro de 2012

Windows 7 e seus arquivos JAR

Digamos que você tenha um programa Java armazenado em um arquivo JAR. Para executar seu programa em qualquer sistema operacional, basta executar:

java -jar seu_arquivo.jar

E tudo está resolvido.

Quem usa Windows geralmente não acha uma janela de terminal muito cômoda. O que você faz então? Cria uma associação de extensão no Windows Explorer! Isso é fácil e fazemos isto já faz tanto tempo que não lembro quando comecei a fazer isso.

Mas mais uma vez a Micro$oft quis inovar! No Windows 7 já não é possível associar uma extensão a um programa e editar as propriedades dessa associação (como por exemplo, executar java -jar <parâmetro> aonde parâmetro é o arquivo em que você deu duplo clique).

E por que isso? Segurança? O usuário comum do Windows é burro demais para fazer isto sozinho?

Eu não sei dizer a razão... mas agora se você quiser fazer a mesma coisa para poder executar aquele seu programa Java dentro de um JAR com um simples duplo clique você deve abrir o seu editor de registro favorito e mandar brasa em uma das muitas, mas muitas chaves existentes dentro do pedaço de m¨%#@da chamado Registry do Windows. Olha só como ficou a nova associação de extensões no Windows 7:

Com um único screenshot já consegui mostrar tudo o que você consegue fazer. Quase nada.

Recorri ao santo Google e descobri o programa Jarfix (http://johann.loefflmann.net/en/software/jarfix/index.html#Download) que faz este trabalhinho ingrato para você. O programa é freeware, é pequeno e resolve rapidamente esta questão de associação de arquivos JAR.

Agora já posso editar as tags dos meus arquivos MP3 com tranquilidade usando o Fixtag (http://fixtag.sourceforge.net/)!

segunda-feira, 13 de fevereiro de 2012

Adios becape do Windows!

É muito provável que você um dia na vida tenha usado o Windows XP.

É esperado que você faça becape dos dados importantes do seu computador (você faz, não?) mas o que acontece quando você tem arquivos de becape feitos pela ferramenta de becape do Windows XP (vide http://support.microsoft.com/kb/320820) e depois faz upgrade para um sistema operacional mais recente da Micro$oft?

A resposta é simples: você se dá mal!

À partir do Windows 2003 esses arquivos de becape não são mais suportados pela Micro$oft, que em sua grandiosa genialidade, chegou a conclusão que os arquivos de becape não são mais necessários quando ela descontinua um produto.

Eu tentei recuperar um arquivo de becape antigo pelo Windows 7 e descobri à duras penas que não dá para fazer isto mais já que para instalar o programa que, em teoria daria suporte a isto, descobri que eu ainda precisava de um recurso de "Removable Storage Manager" que simplesmente não existe no Windows 7 (vide este link aqui). Boa Micro$oft, mais uma cagada para seu currículo!

Depois me perguntam porque eu gosto tanto de software livre: alguma boa alma desenvolveu um programa em C chamado mtftar (http://gpl.internetconnection.net/mtftar.readme) que felizmente resolveu o problema para mim. Bastou usar o dual boot do meu computador, passar para o Ubuntu e executar a sequência de comandos abaixo em um shell:

tar xzvf mtftar.tar.gz
cd mtftar
make

E depois é só seguir as instruções do programa para recuperar os arquivos. A única coisa que faltou para a solução ser perfeita foi um pacote DEB para Debian GNU Linux e similares. Alguém aí se habilita?

quinta-feira, 3 de novembro de 2011

Usando o Microsoft Excel para criar um XML Schema

Editar um XML é relativamente simples, correto? E criar um XML Schema à partir de um arquivo XML?

Eu nunca conheci um profissional por estes lados que tivesse a sua disposição uma ferramenta como o Altova XMLSpy para editar alguma coisa em XML. Os gerentes geralmente devem achar que o Notepad.exe é suficiente para qualquer coisa!

Criar um Schema manualmente pode ser um processo chato... senão doloroso. Aqui vai uma dica para os analistas de sistemas humildes que só dispõe de uma licença do Microsoft Excel para fazer este trabalho árduo.O Excel consegue (pelo menos à partir da versão 2003) trabalhar com arquivos XML com bastante desenvoltura. Você pode importar um arquivo XML tranquilamente. Observe o arquivo XML abaixo:



Agora basta abrir o arquivo pelo Excel utilizando uma das opções para abertura de arquivo. Você verá a caixa de diálogo abaixo. Escolher qualquer uma das opções deve ser suficiente.


Perceba que uma mensagem será exibida informando que não existia um Schema associado ao XML, portanto o Excel resolveu criar um para você.



O resultado final é essa coisa aqui:



O schema não vai ser mostrado diretamente, então é aqui que vem a dica:
  1. Pressione a combinação ALT+F11 para abrir o editor de Visual Basic.
  2. Na janela "Immediate", digite "Print ActiveWorkbook.XmlMaps(1).Schemas(1).Xml" e pressione enter. Se a janela não estiver sendo mostrada, use o menu View para abilitar a janela.
  3. Pressione enter. O Schema será mostrado logo abaixo na janela Immediate.
O Schema do XML de exemplo ficará da seguinte forma:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element nillable="true" name="contactPlanning"><xsd:complexType><xsd:sequence minOccurs="0"><xsd:element minOccurs="0" nillable="true" type="xsd:string" name="UF" form="unqualified"></xsd:element><xsd:element minOccurs="0" nillable="true" type="xsd:integer" name="CRM" form="unqualified"></xsd:element><xsd:element minOccurs="0" nillable="true" type="xsd:integer" name="period" form="unqualified"></xsd:element><xsd:element minOccurs="0" nillable="true" type="xsd:string" name="sector" form="unqualified"></xsd:element><xsd:element minOccurs="0" nillable="true" type="xsd:string" name="product" form="unqualified"></xsd:element><xsd:element minOccurs="0" nillable="true" type="xsd:string" name="segment" form="unqualified"></xsd:element><xsd:element minOccurs="0" nillable="true" type="xsd:integer" name="contactsCycle" form="unqualified"></xsd:element><xsd:element minOccurs="0" nillable="true" type="xsd:integer" name="contactsYear" form="unqualified"></xsd:e
lement><xsd:element minOccurs="0" nillable="true" type="xsd:string" name="action" form="unqualified"></xsd:element><xsd:element minOccurs="0" nillable="true" type="xsd:integer" name="externalId" form="unqualified"></xsd:element><xsd:element minOccurs="0" nillable="true" type="xsd:integer" name="priority" form="unqualified"></xsd:element></xsd:sequence></xsd:complexType></xsd:element></xsd:schema>

Não exatamente muito bonito de ler... mas melhor do que escrever isto tudo manualmente. Outra coisa que você vai reparar é que o Schema é bastante permissivo. Provavelmente você terá que trabalhar em alguns atributos para resolver isto, mas em meros segundos você já ganhou uma boa ajuda do Excel!

quinta-feira, 27 de outubro de 2011

Descobrindo por onde vaza memória dos seus programas

Estava eu dando um olhada no web site Siebel Unleashed no começo desta semana quando me deparei com o artigo "Memory Leaks in Siebel". O artigo é interessante pois agrega informação espalhada por vários documentos encontrados somente no My Oracle Support. Mas o que mais me chamou a atenção no artigo não foi o que já está documentado por aí.

O autor do artigo (Timur Vafin)  criou uma série de scripts (sendo um deles em Perl) para analisar código eScript recuperado do banco de dados do repositório do Siebel e procurar por variáveis do tipo Object (ou derivados) que de acordo com as boas práticas (de sanidade) deveriam ser eliminadas com um simples var = null dentro do bloco finally de cada programa/função.

Pois bem, eu resolvi botar o programa para rodar e ver o que acontecia. Me desapontei por achar alguns tropeços básicos no que se trata de Perl (nada de pragmas como warnings e strict a a total falta de conhecimento de DBI) mas depois de algumas linhas de código a mais e correções aqui e ali e o script Perl passou a rodar sem problemas no meu ambiente de desenvolvimento sem maiores sustos e com bons resultados!

O script encontrou um monte de tranqueiras no meu repositório... coisa que já faz muito tempo que ninguém olha mas está lá... como uma mina terrestre esperando alguém pisar encima para explodir!

Caso você não saiba, algum componente do seu servidor Siebel pode estar tendo problemas de vazamento de memória e o processo acaba sendo morto pelo sistema operacional para evitar que o servidor fique sem memória RAM. No caso de eScript, fatalmente será algum AOM que estiver rodando no servidor.

Eu fiquei tão contente com o resultado que entrei em contato com o Timur e hoje acabo de criar um projeto para o programa no Google Code. O resultado pode ser visto aqui.

O parser do programa ainda é bem rudimentar (baseado em expressões regulares) e provavelmente pode apresentar falsos positivos mas certamente já é uma mão na roda para começar a desenterrar essas "minas terrestres".

Gostou da ideia também? Estou aceitando contribuidores para o projeto (ei rodar testes também é contribuir!) e mesmo que você só estiver interessado em dar uma olhada no código basta acessar o repositório SVN do Google Code em:

http://code.google.com/p/siebel-code-analyzer/source/browse/#svn%2Ftrunk

Até mais!

quarta-feira, 19 de outubro de 2011

Fazendo melhor uso do srvrmgr.exe

O aplicativo de linha de comando srvrmgr.exe nunca foi lá de muito sucesso com o Siebel. Mas qualquer SADMIN com algum tempo de experiência acaba descobrindo na marra que a interface gráfica tem suas limitações e o srvrmgr é um excelente complemento para ela.

Uma das utilizações mais óbvias do srvrmgr é quando o AOM utilizado no servidor está fora do ar e você não tem um cliente dedicado configurado. Outro uso é para automatizar tarefas, mas isso é um assunto para outro dia.

A dica que vou escrever aqui hoje é sobre o uso interativo do srvrmgr. Estou assumindo que você está usando Windows. Se você está usando Linux (algum outro UNIX like), por favor me avise para aonde eu mando meu currículo porque eu não aguento mais trabalhar com Siebel em Windows. :-D

Em primeiro lugar, vamos falar de configuração de codificação de caracteres. Suponhamos que seu sistema tenha configurado a aplicação em PTB (Português do Brasil) e você roda um simples list comp no srvrmgr:

srvrmgr> list comp

CC_ALIAS           CC_NAME                               CG_ALIAS      CC_RUNMODE   CP_DISP_RUN_STATE
-----------------  ------------------------------------  ------------  -----------  -----------------
ClientAdmin        Client Administration                 System        Background   Ativado
CommConfigMgr      Communications Configuration Manager  CommMgmt      Batch        Ativado
CommOutboundMgr    Communications Outbound Manager       CommMgmt      Batch        Ativado
CommSessionMgr     Communications Session Manager        CommMgmt      Batch        Ativado
DbXtract           Database Extract                      Remote        Batch        Ativado
EAIObjMgr_enu      EAI Object Manager (ENU)              EAI           Interactive  Ativado
MailMgr            Email Manager                         CommMgmt      Background   Ativado
EIM                Enterprise Integration Mgr            EAI           Batch        Ativado
FSMSrvr            File System Manager                   System        Batch        Ativado
GenNewDb           Generate New Database                 Remote        Batch        Ativado
GenTrig            Generate Triggers                     Workflow      Batch        Ativado
PageMgr            Page Manager                          CommMgmt      Background   Ativado
PDbXtract          Parallel Database Extract             Remote        Batch        Em execuþÒo
RepAgent           Replication Agent                     Remote        Background   Ativado
ServerMgr          Server Manager                        System        Interactive  Em execuþÒo
SRBroker           Server Request Broker                 System        Interactive  Em execuþÒo
SRProc             Server Request Processor              System        Interactive  Em execuþÒo
SynchMgr           Synchronization Manager               Remote        Interactive  Ativado
TxnMerge           Transaction Merger                    Remote        Background   Em execuþÒo
TxnProc            Transaction Processor                 Remote        Background   Em execuþÒo
TxnRoute           Transaction Router                    Remote        Background   Em execuþÒo
UpgKitBldr         Upgrade Kit Builder                   SiebAnywhere  Batch        Ativado
WorkActn           Workflow Action Agent                 Workflow      Background   Ativado
WorkMon            Workflow Monitor Agent                Workflow      Background   Ativado
WfProcBatchMgr     Workflow Process Batch Manager        Workflow      Batch        Ativado
WfProcMgr          Workflow Process Manager              Workflow      Batch        Ativado
ePharmaObjMgr_enu  ePharma Object Manager (ENU)          LifeSciences  Interactive  Ativado
ePharmaObjMgr_esn  ePharma Object Manager (ESN)          LifeSciences  Interactive  Ativado
ePharmaObjMgr_ptb  ePharma Object Manager (PTB)          LifeSciences  Interactive  Ativado

Tudo certo, exceto pelos caracteres esquisitos. Bem, o problema é a codificação de página padrão do prompt de comando do Windows. A codificação ativa padrão é 850 e isso não ajuda muito com caracteres acentuados da língua portuguesa. Para mudar isto, basta usar o comando chcp no CMD.exe com a opção 1252:

I:\>chcp 1252
Active code page: 1252

Isso resolverá seus problemas com codificações de página. Se você tiver saída com alguma outra configuração exótica, pesquise sobre o assunto para conseguir visualizar a saída do programa de forma adequada. Claro que ficar digitando isso toda santa vez vai ser trabalhoso, mas nada que criar um script para lhe ajudar a fazer isto (você está usando um script, não? Por favor não me diga que você digita todos aqueles parâmetros toda hora!).

A outra questão é trabalhar com senha: se você precisa utilizar um login e senha para se autenticar no srvrmgr é sempre uma boa idéia se preocupar como utilizar sua senha. Salvar em um script não é legal e digitar no terminal também não, afinal papagaio de pirata também é uma falha de segurança!

Existem diversas formas de resolver isto, mas o melhor é desabilitar o ECHO ao se digitar no terminal. Isso pode ser feito de diversas formas (vide sua linguagem de programação favorita). Eu, por exemplo, criei o script em Perl abaixo para fazer isto pra mim:

use warnings;
use strict;
use Term::ReadKey qw(ReadMode);
use Win32::Process;

my $server     = '';
my $gateway    = '';
my $enterprise = '';
my $user       = '';
my $srvrmgr    = 'sea752\\client\\BIN\\srvrmgr.exe';

system('chcp 1252');

print 'Type your password to connect to Siebel Server: ';
ReadMode(2);
my $password = <STDIN>;
ReadMode(0);

chomp($password);

print "\n\n";

my $process;

Win32::Process::Create( $process, $srvrmgr,
    "srvrmgr /e $enterprise /g $gateway /u $user /p $password",
    0, NORMAL_PRIORITY_CLASS, '.' )
  or die errorReport();

$process->Wait(10);

sub errorReport {

    print Win32::FormatMessage( Win32::GetLastError() );

}

Assim a vida fica mais fácil!

Vale lembrar que se você utilizar a função spool do srvrmgr, ela provavelmente vai assumir a codificação do seu banco de dados (não tenho certeza disto, mas meu banco é UTF-8 e a saída salva tem a mesma codificação de dados).