5 passos para começar seus scripts no Eclipse com e sem Citrix.
--
Fala pessoal tudo bem ?
Vou tentar explicar o mínimo para começar a fazer seus scripts no ESAPI (Eclipse Scripting API). Estarei usando o Eclipse v15.6 , mas todos os scripts neste artigo serão reutilizáveis na maior parte das versões acima da 11, pois não iremos editar informações, apenas pegá-las.
Todas as explicações serão baseadas projetos simples cobrindo como fazer e rodar :
Rodar um hello world no Visual Studio.
Scripts de arquivo único direto no eclipse para usar em um paciente por vez;
Scripts compilados em biblioteca para um paciente por vez (direto do Eclipse).
Executáveis para rodar todo o banco de dados (usando citrix);
Gerenciar duas versões do executável com o Git e testá-las.
Você não precisa saber programar pra fazer um script pro Eclipse. Simplesmente procurar no Google, tentar e errar, tentar e errar até fazer o primeiro que da certo. A linguagem que somos obrigados a usar é o C#, existem cursos baratos no udemy que são mais que suficientes.
Antes de tudo vamos baixar o IDE do visual studio que é basicamente obrigatório. Você pode baixar no seu computador mesmo ou no computador do trabalho se a TI deixar.
Baixe o visual studio comunity 2019 nesse link:
Quais pacotes instalar:
Os mais importantes são desenvolvimento para desktop com .NET e desenvolvimento com plataforma universal windows.
O básico do básico do C#
Dando um olá mundo com visual studio e C#.
Abra o visual studio e crie um novo projeto:
Escolha um aplicativo de console para .NET Framework
Escolha um nome para o projeto e inicie ele:
Use o framework 4.5;
Ele vai iniciar assim.
Declarando uma variável
Dentro dos colchetes da função Main, escreva:
string message = "Hello World";
Você está declarando pro sistema alocar memória para uma string que tem nome message.
Toda vez que você quiser reutilizar a mensagem “Hello World” você pode se referir a variável message.
Primeiro a gente vai imprimir a mensagem no console.
Console.WriteLine(message);
Aperte Ctrl+F5
Seu primeiro programa já está funcionando.
MessageBox
Até nossa aplicação do ESAPI Executável, não usaremos o console. Então vamos usar o MessageBox do windows para imprimir algumas informações.
Para usar o MessageBox faça o seguinte:
Adicione a seguinte linha de comando abaixo do seu código original:
MessageBox.Show(message);
Ao fazer isso perceberemos um erro:
Clique com o botão direito no erro:
Pressione Ações Rápidas e Refatorações ou Ctrl+. (Esse comando é muito útil);
Adicione o a referência a biblioteca do Windows Form.
Ela vai aparecer lá em cima agora:
Aperte Ctrl + F5 novamente:
Você acabou de usar a biblioteca MessageBox com sucesso, e não precisa mais do console pra entender as saídas do seu código por enquanto.
Avançando um pouco e iniciando :
O ESAPI é uma biblioteca que liga o sistema de planejamento ao C#, da mesma forma que a biblioteca windows form conecta o C# a extensão de janelas do sistema operacional. As bibliotecas contém linhas de programação que fazem essa intermediação sem que nós precisemos nos preocupar com isso. No ESAPI existem classes que ligam o objetos do Eclipse ao código apresentado ao usuário (NÓS). Então se queremos pegar informação do nome do paciente temos que acessar o objeto do Paciente (Patient).
Objeto
Resumidamente é a instancia de um tipo de uma variável mais elaborado. Ele vem de uma classe que é feita por alguém. Toda classe é rastreada a tipos básicos como números, strings, booleanos. O legal do visual studio é que quando você tem um objeto, você pode acessar suas propriedades antes da compilação do código.
Exemplo de objeto
Crio a classe para uma pessoa:
class Pessoa{public string Nome { get; set; }public string SobreNome { get; set; }public int Idade { get; set; }public void Print(){MessageBox.Show(Nome + " " + SobreNome + " " + Idade.ToString());}}
Instancio uma nova pessoa (objeto), agora temos uma variável do tipo Pessoa com nome pessoa que tem o conteúdo seguinte:
Pessoa pessoa =
new Pessoa { Nome = "Joseph", SobreNome = "Logan", Idade = 44 };
Agora posso usar a função print da pessoa:
pessoa.Print();
Ctrl + F5:
Como o ESAPI na prática funciona:
Plugins
O script depende do eclipse instalado no computador. Se você roda um script de dentro do eclipse, ele só acessa a informação do paciente que tem a janela aberta. Existe um objeto da classe ScriptContext que faz a intermediação ao C# dos elementos abertos no caso.
O eclipse que compila o código dentro dele nesses casos, então não vamos usar a função Main() como entrada.
Para explorar nosso primeiro plugin, Crie um novo projeto da mesma forma que o hello world. Porém ele será agora uma Biblioteca de Classes(.NET Framework) Com nome HelloWorldPlugin.
Na sua solução, clique com o botão direito em referências:
Pressione em Procurar para achar a referência dos VMS.TPS que fará a conexão do computador que o eclipse está instalado ao compilador do C#.
No geral, a biblioteca VMS.TPS está localizada no computador que o Eclipse está instalado. Na seguinte pasta:
C:/Arquivos de Programas(x86)/Varian/RTM/versao/esapi/API
Se seu eclipse é local:
Localize essa pasta e adicione as referências:
Se CITRIX:
Se você possui CITRIX, o eclipse está instalado no computador virtual, a possibilidade nesse caso é copiar os arquivos que estão na estação virtual.
Lembre da dica (vamos usar esse atalho mais vezes) :
Abra o Planejamento Externo (External Beam Planning)/Tools/Scripts
Pressione Open Folder em System Scripts:
Abrirá o explorer do computador virtual que tem o Eclipse instalado:
Copie os seguintes arquivos uma pasta qualquer do computador que tem o visual studio instalado.
AlgumaPasta/(VMS.TPS.Common.Model.API.dll)
AlgumaPasta/(VMS.TPS.Common.Model.Types.dll)
E realize os mesmos passos após as dlls estarem copiadas localmente para adicionar a referência. Elas podem estar em qualquer pasta agora.
Vamos ao código:
O ESAPI SEMPRE precisa da seguinte forma para os plugins, exatamente estes nomes:
namespace VMS.TPS{
public class Script{public void Execute(ScriptContext context){//Code here}
}
}
Note que vai acontecer a mesma coisa do MessageBox com o ScriptContext! Ele vai reclamar que ele não existe. Então clique Ctrl + . e resolva o problema.
Note que ele adiciona a dll do API.
Se você quiser, antes de qualquer código escrito, escrever esses comando no início do programa.
using VMS.TPS.Common.Model.API;
using VMS.TPS.Common.Model.Types;
Também resolveria o problema. Mas aprender a consertar os bugs com Ctrl + . é muito importante.
Quase lá
Vamos escrever as primeiras linhas no single file plugin. E aprender a rodar no Eclipse.
Vamos agora abrir um paciente pelo Planejamento Externo. Qualquer um que tenha um plano com dose calculada:
No meu caso, uma radiocirurgia de múltiplas lesões:
O código fará o seguinte: O contexto, que é a janela aberta, possui um plano de Radioterapia Externa que está aberto no momento. Vamos acessar esse plano pelo script e iremos criar uma variável de mensagem com o nome do plano. Depois usar um MessageBox para imprimir esse nome de plano.
Adicione as seguintes linhas à função Execute(ScriptContext context):
ExternalPlanSetup plan = context.ExternalPlanSetup;
//objeto do planostring message = plan.Id;MessageBox.Show(message);
// Mostrar a mensagem
Conserte o problema do MessageBox (Ctrl + .) com a biblioteca Presentation Framework, diferentemente da windows forms que usamos anteriormente.
O Forms não vai funcionar no plugin de arquivo único porque essa biblioteca não existe na memória do eclipse.
Primeiro teste:
No parte de ferramentas e scripts (/Tools/Scripts), utilize o marcador de Open Folder e localize onde está o arquivo Class1.cs e clique duas vezes nele.
Lembre que se você está usando o Citrix, você tem que por o arquivo onde o computador do Citrix que o eclipse está instalado possa achá-lo. Se o client é o computador onde você programou, então fica fácil. Se não use um pendrive ou uma pasta compartilhada.
Clique em Run ou duas vezes em Class1.cs:
Com sucesso rodamos nosso primeiro script de arquivo único.
Experimente agora trocar, a string de somente o nome do plano para o sobrenome do paciente e do plano.
Substitua a linha que declara message por essa linha:
string message = context.Patient.LastName + " " + plan.Id;
Salve e rode novamente:
Agora você usar essa estrutura pra fazer quase tudo. Porém temos algumas limitações.
Limitações do plugin de arquivo único:
Não pode ter bibliotecas que não estão pre-instaladas no Eclipse. Isso significa que se queremos fazer um gráfico por exemplo não vamos conseguir. Já que não existe ferramenta integrada de gráficos no C#. (Farei um post de como fazer gráficos).
Se limitar a um arquivo único. Separação de código é muito importante em C# e isso é completamente travado pela estrutura do single file plugin. Existem arquivos que deveriam estar separados que estão juntos, gerando scripts de 10000 linhas. Muitas vezes vamos precisar fazer interfaces gráficas para nossas aplicações, e o WPF que é muito bom nisso, precisa que tenha mais de um arquivo para funcionar.
Para solucionar essa problemática, a Varian permite que você crie scripts compilados, isto é, transformar seu código em uma biblioteca fake. Que tem um ponto de entrada igual ao single file plugin e é chamado de binary plugin.
Criando nosso primeiro binary plugin:
Para reforçar que estamos usando bibliotecas externas que não existem no eclipse, vamos baixar um biblioteca chamada RandomNameGenerator.
Na aba de solução, clique com o botão direito em referências:
Logo, aperte em gerenciar pacotes do NuGet. É a fonte de onde vem bibliotecas externas no C#.
Procure por RandomNameGeneratorLibrary
Clique em instalar.
Agora podemos usar essa biblioteca externa.
Agora deixe seu código deste jeito:
namespace VMS.TPS{public class Script{public void Execute(ScriptContext context){ExternalPlanSetup plan = context.ExternalPlanSetup;//objeto do planovar personGenerator = new PersonNameGenerator();var name = personGenerator.GenerateRandomFirstAndLastName();string message = "The patient last name is not " + name + "his last name is " + plan.Course.Patient.LastName;MessageBox.Show(message);// Mostrar a mensagem}}}
Use o Ctrl + . para importar a biblioteca RandomNameGeneratorLibrary;
using RandomNameGeneratorLibrary;
Ou adicione isso antes do namespace.
Pequena nota:
Perceba que eu acessei o nome do paciente pelo Plano/Curso/Paciente. Não mais pelo Contexto. O ideal é que você use o mínimo possível do contexto para poder reaproveitar código nos executáveis, onde não existe contexto.
Testando se é verdade o que eu falei:
Salve o arquivo Class1.cs e tente rodar ele no paciente novamente.
Ele reclama exatamente da biblioteca externa.
Compilação:
No visual studio, na aba de solução, clique com botao direito no nome do projeto e clique em Propriedades:
Essa tela será apresentada:
Troque o nome do projeto de Algo para Algo.esapi:
Na aba compilar, mude destino da plataforma para x64 e mude o caminho de saída para vazio (opcional):
Salve.
E compile, com Ctrl+Shift+B. Ou no menu compilação, compilar solução.
Se voce mudou o caminho da pasta para vazio, seu projeto foi compilado na mema pasta que está o arquivo Class1.cs.
Rode o arquivo .esapi.dll:
Rode mais uma vez:
Estamos certos de que a biblioteca RandomNameGeneratorLibrary está sendo aleatória mesmo!
O que aconteceu agora, foi que ao compilar nosso código tem acesso a biblioteca que também foi compilada, em que ambos estão na mesma pasta.
Se você retira o arquivo RandomNameGeneratorLibrary.dll, e reinicia o Eclipse:
Se não tivesse reiniciado o Eclipse, o código continuaria rodando normal. Vamos entender o por quê agora.
Quando um programa é carregado na memória do ESAPI durante a existência daquela sessão do eclipse no nosso computador, o nome de assembly e dos assemblies que o programa que você rodou é dependente, ficam guardados durante a sessão como algo imutável. Então, se a gente fizer qualquer mudança e tentar recompilar no visual studio. Olha o que vai acontecer.
Adicionando ao código:
message += "\n Nonono";
MessageBox.Show(message);
Compilo novamente (Ctrl + Shift + B):
Aquele nome de assembly está bloqueado.
Como resolver isso:
Reiniciar o Eclipse (Close all);
Se o assembly do RandomNameGeneratorLibrary não estivesse sendo chamado e dado na memória como não encontrado. Como acontece na maior parte dos casos.
Poderiamos apenas:
Mudar o nome do assembly;
Compilo novamente (Ctrl + Shift + B):
Rodo o novo:
E funcionaria novamente:
O que levar pra casa:
Binários resolvem o problema de bibliotecas externas e dos arquivos sem separação de responsabilidade, porém vem com diversos como:
Necessidade de reiniciar o eclipse ou mudar o nome de assembly para recompilação a cada mudança;
Eles permitem a realização de aplicativos WPF para criação de interface gráfica.
Executáveis:
Se você chegou até aqui, você está interessado em varrer o banco de dados.
Os executáveis funcionam igual ao primeiro exemplo de C# você compila e roda direto do computador, ele abre o console ou uma janela pra te informar sobre a execução, então vamos nos livrar do MessageBox. A biblioteca VMS.TPS conecta o C# aos pacientes pelo objeto da classe VMS.TPS.Application. Essa biblioteca acha o banco de dados dentro do computador que tem o Eclipse instalado, então para usuários de CITRIX você vai compilar no seu computador com visual studio, e copiar todos os arquivos que vem junto com a compilação pro computador do CITRIX.
Vamos criar um novo aplicativo do console .NET Framework
Vou chamá-lo de MultiPatientExecutable.
Vamos pegar as referências que nem nos plugins para as bibliotecas do VMS.TPS.
E vamos montar o template de código para o executável que varre todos os pacientes do banco de dados e imprime no console o Id dos planos em que a dose calculada é valida:
using VMS.TPS.Common.Model.API;using VMS.TPS.Common.Model.Types;namespace MultiPatientExecutable{class Program{[STAThread]public static void Main(string[] args){try{using (Application app = Application.CreateApplication()){Execute(app);}}catch (Exception e){Console.Error.WriteLine(e.ToString());Console.Read();}}public static void Execute(Application app){//Console.Read();foreach (var summary in app.PatientSummaries){Patient patient = app.OpenPatient(summary);// Code hereIEnumerable<PlanSetup> isDoseOk =
patient.Courses.SelectMany(e => e.PlanSetups).Where(e => e.IsDoseValid);string message = string.Join("\n", isDoseOk.Select(e => e.Id));Console.WriteLine(message);
Console.ReadLine();
app.ClosePatient();}}}}
Vamos compilar com as seguintes configurações de compilação:
Compilamos com Ctrl+Shift+B.
Se o eclipse é local você roda simplesmente o arquivo executável, clicando duas vezes:
Se o eclipse for CITRIX tem que copiar a pasta bin para o disco local do computador onde o citrix ta instalado.
Use o mesmo truque ensinado lá em cima tanto para copiar quanto pra executar.
ExternalBeamPlanning/Tools/Scripts/SystemScripts/OpenFolder/ → Garante acesso ao explorador de arquivos do citrix que possui o Eclipse instalado.
De um clique duplo e o script irá imprimir o nome dos planos com dose válida para cada paciente. A cada enter que o usuário da ele vai para o próximo paciente.
Nota1: O programa deve ser rodado no disco local do computador que o CITRIX está instalado
Nota: Todo paciente que é aberto tem que ser fechado antes de abrir o próximo. Por isso o app.ClosePatient().
Estamos bem avançados agora com o nosso executável, porém imagine que você quer pegar esses planos para determinados pacientes que você já tem guardado numa planilha. Esses pacientes possuem um ID único. E você exportou os IDs linha por linha pra um arquivo de texto, Ids.txt.
1235
225
12358
7777
8880
5555
Como agora eu uso essa lista de pacientes para fazer isso?
Gerenciando versões do código com o GIT direto do visual studio.
Nós não precisamos criar outro projeto. Vamos fazer o seguinte, criar uma cópia do código no mesmo projeto com o Git.
Guia de Git : (https://rogerdudler.github.io/git-guide/index.pt_BR.html).
Pro git, essa cópia que tem o nome de branch (ramificação).
Vamos iniciar o repositório no canto direito inferior em Adicionar ao controle de Código-Fonte:
Pressione controle do Git:
Será apresentado para você essa visão:
E essa :
Clique no simbolo ao lado do nome master e selecione novo branch:
Vamos colocar o nome da branch como patient_list e pressionar em criar ramificação:
Agora você está na branch patient_list:
Da pra alternar entre master e patient_list e quantas branches você quiser.
Agora a branch atual sofrerá as modificações que queremos. Agora ao invés de salvar com Ctrl+S, você pode commitar suas mudanças de código através do lápis e reportar o que você mudou no código. Como vamos fazer.
Adicionando o controle de quais pacientes vão ser abertos:
Vamos fazer mudanças substanciais, mas não se assuste:
Copie o código abaixo e cole em cima do conteúdo do arquivo Program.cs.
using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;using VMS.TPS.Common.Model.API;using VMS.TPS.Common.Model.Types;using Application = VMS.TPS.Common.Model.API.Application;namespace MultiPatientExecutable{class Program{[STAThread]public static void Main(string[] args){try{using (Application app = Application.CreateApplication()){SelectPatientList(app);(app);}}catch (Exception e){Console.Error.WriteLine(e.ToString());Console.Read();}}public static void SelectPatientList(Application app){Console.WriteLine("Select the folder that contain the txt with the patients IDs.");var file = "";OpenFileDialog openFileDialog1 = new OpenFileDialog();if (openFileDialog1.ShowDialog() == DialogResult.OK){file = openFileDialog1.FileName;}try{Execute(app, file);}catch (Exception){MessageBox.Show($"Failed for file {file}, maybe it is empty");}}public static void Execute(Application app, string file){var readAll = File.ReadAllLines(file).ToList();//Console.Read();foreach (var id in readAll){Patient patient = app.OpenPatientById(id);// Code hereIEnumerable<PlanSetup> isDoseOk =patient.Courses.SelectMany(e => e.PlanSetups).Where(e => e.IsDoseValid);string message = string.Join("\n", isDoseOk.Select(e => e.Id));Console.WriteLine(message);Console.ReadLine();app.ClosePatient();}}}}
Agora vamos salvar com o commit:
Clique no botão no lápis:
Escreva sua mensagem de commit:
Mudei meu código para escolher os pacientes
Se você quiser saber as alterações feitas de antes para agora clique duas vezes em Program.cs:
Pressione confirmar tudo e salve:
Você fez seu commit, seu código está salvo!
Compile novamente com Ctrl+Shift+B:
Rode o programa de novo:
Selecione o arquivo:
Esse é o output.
Obrigado pela atenção.
Executáveis com contexto:
Uma coisa que talvez você não saiba: Executáveis podem até simular um plugin, aí você escapa dos problemas de assembly do eclipse pros binários, tendo um binário que executa e passa as informações do contexto para o executável (.exe), que não vai ter esse problema. Isso ficará pra outro post.