Factory com CDI

Neste artigo, a partir de um exemplo simples de fábrica (Factory) na linguagem Java, vou  mostrar como implementar esta mesma fábrica, porém para criar objetos gerenciados pelo container, usando CDI.

Como exemplo vou usar uma fábrica de formas que, dado um tipo de forma, retorna uma instância deste tipo.

Para este exemplo teremos duas formas, o retângulo e o círculo, listadas na enumeração ShapeType.

public enum ShapeType {
   RECTANGLE, CIRCLE
}

A classe abstrata Shape representa uma forma genérica. Shape possui uma dependência do tipo ShapeDependency, que deve ser passada como parâmetro para o seu construtor.

public abstract class Shape {

   private ShapeDependency dependency;

   public Shape(ShapeDependency dependency) {
      this.dependency = dependency;
   }

   public ShapeDependency getDependency() {
      return dependency;
   }
}

A classe ShapeDependency por sua vez, possui a propriedade name, a qual deve ser  passada como parâmetro para o seu construtor.

public class ShapeDependency {

   private String name;

   public ShapeDependency(String name) {
      this.name = name;
   }

   public String getName() {
      return name;
   }
}

As classes Rectangle e Circle são formas específicas, subclasses de Shape. Elas instanciam ShapeDependency nos seus construtores e passam esta instância para o construtor da superclasse Shape, já recebendo o name correto.

public class Rectangle extends Shape {

   public Rectangle() {
      super(new ShapeDependency("Rectangle dependency"));
   }
}

public class Circle extends Shape {

   public Circle() {
      super(new ShapeDependency("Circle dependency"));
   }
}

Por fim, a fábrica ShapeFactory possui o método create que retorna uma instância da classe Shape, de acordo com o ShapeType recebido por parâmetro.

public class ShapeFactory {

   public Shape create(ShapeType type) {
      if(RECTANGLE.equals(type)){
         return new Rectangle();
      }
      if(CIRCLE.equals(type)){
         return new Circle();
      }
      return null;
   }
}

Até aqui tudo tranquilo, nada diferente de uma fábrica comum. Mas e se a instância retornada pela fábrica possui uma dependência gerenciada pelo container?

Para ilustrar este caso, Shape terá a sua dependência injetada por CDI.

public abstract class Shape {

   @Inject
   private ShapeDependency dependency;

   public ShapeDependency getDependency() {
      return dependency;
   }
}

Rectangle e Circle teriam de configurar a dependência num método anotado com @PostConstruct, pois este será executado pelo container após a injeção da dependência, ao contrário do construtor, que é executado antes, o que ocasionaria NullPointerException.

public class Rectangle extends Shape {

   @PostConstruct
   public void setUp() {
      dependency.setName("Rectangle dependency");
   }
}

public class Circle extends Shape {

   @PostConstruct
   public void setUp() {
      dependency.setName("Circle dependency");
   }
}

ShapeDependency teria o valor da propriedade name configurado num setter, pois o container usa apenas o construtor vazio (sem parâmetros) para instanciar as classes que ele gerencia.

public class ShapeDependency {

   private String name;

   public void setName(String name) {
      this.name = name;
   }

   public String getName() {
      return name;
   }
}

Neste novo contexto, o problema é que o método create de ShapeFactory não pode mais criar a instância de Shape com um comando new, pois esta nova instância não terá sua dependência injetada, já que com este comando é você que está gerenciando o ciclo de vida da instância, não o container.

Você também não pode simplesmente injetar Shape na ShapeFactory, pois Shape é uma classe abstrata e o container não saberia qual subclasse injetar, Rectangle ou Circle.

E mesmo que o container injetasse uma delas arbitrariamente, ele o faria ao instanciar ShapeFactory, e nós só sabemos de qual subclasse de Shape queremos uma instância durante a execução do método create, a partir do parâmetro ShapeType recebido.

A solução é usar um recurso que o CDI nos proporciona, que permite avisar ao container que ele não deve injetar a dependência (Shape) ao instanciar ShapeFactory, que é a interface Instance<T>. Esta interface ainda nos permite, no momento apropriado, selecionar a subclasse desejada através do método select, e obter a instância desta classe através do método get.

public class ShapeFactory {

   @Any
   @Inject
   private Instance<Shape> shape;

   public Shape create(ShapeType type) {
      if(RECTANGLE.equals(type)){
         return shape.select(Rectangle.class).get();
      }
      if(CIRCLE.equals(type)){
         return shape.select(Circle.class).get();
      }
      return null;
   }
}

Desta forma temos uma fábrica com o mesmo comportamento da primeira, mas que é capaz de entregar instâncias gerenciadas pelo container.

PS: Note que para funcionar a própria fábrica deve ser gerenciada pelo container.

Le BigoDay


Dia do Bigode, Bigoday ou Mustache Day, são vários nomes para apresentar um movimento que dizem ter iniciado nos Estados Unidos após uma mobilização de alguns barbeiros pelo Mustache Day, este evento chegou ao Brasil por meio de publicitários, e é claro, que pessoas criativas e irreverentes como nós não podíamos ficar de fora.
No dia 19 de dezembro de 2011 aconteceu Le BigoDay Equipe de Desenvolvimento ELSA, sem medo de ser feliz, todos puderam participar do evento inclusive as meninas. Para registrar a data a Equipe dos Bigodões se reuniu em uma Comemoração de Fim de Ano no Instituto de Psicologia da UFRGS e fotografou esse encontro.

Atletas ELSA

Fazendo parte de um estudo sobre saúde, estamos em continua preocupação com o bem-estar próprio. O esporte, então, acaba sendo uma das melhores opções para o mens sana in corpore sano. Alguns membros da equipe levam isso muito a sério e são também atletas. Dois deles foram documentados pelo RBS Esporte, em momentos distintos.

Tiago, o dançarino:


Gabriel, o "Runner" (a partir de 13:40):


Testes com Selenium WebDriver


Selenium WebDriver é a união de duas ferramentas e visa facilitar a criação de testes automatizados para interfaces de aplicações web. A intenção das novas versões do Selenium (a partir da 2.0) é focar no desenvolvedor para que ele gere também os códigos dos testes. Neste post vamos explicar em alguns passos como começar a fazer seus próprios testes.

No nosso exemplo vamos utilizar como linguagem de programação o Java e como ambiente de desenvolvimento o Eclipse. Para executar os testes utilizaremos o JUnit.

O primeiro passo é adicionar os JARs para que consigamos utilizar o WebDriver. Para fazer o download da última versão vá até http://code.google.com/p/selenium/downloads/list. Descompacte o arquivo e adicione os JARs ao seu projeto no Eclipse clicando com o botão direito do mouse em cima da raiz do seu projeto e depois em "Properties".


No menu esquerdo clique em "Java Build Path", selecione a aba "Libraries" e clique em "Add External JARs...". Navegue até a pasta onde estão os arquivos que você fez download, selecione todos e clique em "Abrir". Depois clique em "OK". Pronto, você já pode começar a gerar seus códigos de testes!


A partir de agora começaremos o nosso teste. Neste exemplo vamos mostrar passo a passo como criamos um teste para verificar a interface de autenticação do nosso sistema.

public class LoginTest {
 
 @Test
 public void loginTest() {
  WebDriver driver = new FirefoxDriver();
  driver.get("localhost:8080/elsa/login");
 }

}

Inicialmente nosso teste não verifica nada, apesar de ficar com a barra verde ele apenas abre uma janela do Firefox com o endereço do nosso servidor de testes. Roubamos... mas precisamos partir de algum lugar!
Após verificar que a janela do navegador abriu corretamente a tela de autenticação do sistema vamos tentar realizar a autenticação.

public class LoginTest {
 
 @Test
 public void loginTest() {
  WebDriver driver = new FirefoxDriver();
  
  driver.get("localhost:8080/elsa/login");
  
  driver.findElement(By.id("username")).sendKeys("usuario");
  driver.findElement(By.id("password")).sendKeys("senha");
  driver.findElement(By.id("loginButton")).click();
 }

}

Com o WebDriver buscamos pelos elementos exibidos na tela através dos seus identificadores e inserimos os valores desejados para usuário e senha. Além de buscar pelos elementos da página por seus id’s também é possível buscar pelo nome da tag, do name, do link e até mesmo do estilo CSS aplicado ao elemento.
A partir daqui nos damos conta que em qualquer teste do nosso sistema teremos que passar pela tela de login, então podemos utilizar o padrão chamado de Page Objects. Para tanto, criamos uma classe chamada LoginPage que inicialmente terá um método que fará login no sistema.

public class LoginPage {
 
 public void login(WebDriver driver){
  driver.findElement(By.id("username")).sendKeys("usuario");
  driver.findElement(By.id("password")).sendKeys("senha");
  driver.findElement(By.id("loginButton")).click();
 }
}

E agora sim podemos realizar nosso teste, na classe LoginTest.

public class LoginTest {
 
 public LoginPage loginPage;
 public WebDriver driver;
 
 @Before
 public void setup() {
  loginPage = new LoginPage();
  
  driver = new FirefoxDriver();
  driver.get("localhost:8080/elsa/login");
 }
 
 @Test
 public void loginTest() {
  loginPage.login(driver);
  
  String welcomeMessage = driver.findElement(
    By.xpath("/html/body/div/div[4]/div/ul/li/span")).getText();

  assertEquals("Bem vindo ao Prontuário Eletrônico Online do ELSA.",
    welcomeMessage);
 }

}


Aqui já passamos a instanciar LoginPage e o WebDriver no método setup que está anotado com @Before e, desta forma, é executado sempre antes de cada método anotado com @Test. Além disso, buscamos o valor da mensagem de boas vindas através do método findElement e utilizamos como parâmetro a busca de um elemento presente na página pelo xpath correspondente. Finalmente, fizemos uma asserção para garantir que a mensagem que aparece é a esperada.

Agora que nosso teste está pronto executamos esperando a barra verde que instantaneamente fica vermelha, informando que o nosso teste falhou. Aqui vale uma breve explicação. Como estamos trabalhando com ambiente web, devemos saber que nem sempre a resposta é imediata para as requisições feitas para os servidores onde estão as aplicações. Então o melhor a ser feito para contornarmos o problema é implementarmos uma condição esperada de parada com um timeout, desta maneira o teste pode ser executado com mais confiabilidade.

Para tanto, será necessários fazer algumas mudanças no método loginTest.

@Test
public void loginTest() {
 loginPage.login(driver);
  
 ExpectedCondition<Boolean> expectedCondition = new ExpectedCondition<Boolean>() {
  public Boolean apply(WebDriver webDriver) {
   webDriver.findElement(By.xpath("/html/body/div/div[4]/div/ul/li/span"));
   return true;
  }
 };

 Wait<WebDriver> wait = new WebDriverWait(driver, 15);
 wait.until(expectedCondition);
  
 String welcomeMessage = driver.findElement(
    By.xpath("/html/body/div/div[4]/div/ul/li/span")).getText();

 assertEquals("Bem vindo ao Prontuário Eletrônico Online do ELSA.",
    welcomeMessage);
}

Agora sim, nosso teste é executado e temos a barra verde!
Basicamente implementamos a condição de parada esperada que, neste caso, é o surgimento da própria mensagem de boas vindas do sistema. Depois, instanciamos o wait com o nosso driver e um timeout de 15 segundos e esperamos que a condição seja satisfeita por no máximo 15 segundos, caso contrário o teste falhará.
Claro que o exemplo depende das credenciais utilizadas para realizar o login e apenas ele não garante que a tela de login do nosso sistema está funcionando. Como teste complementar podemos acessar o sistema com uma senha errada e fazer uma asserção em cima da mensagem de falha de login.

PrimeFaces autoComplete weird behavior

A few weeks ago, while changing the behavior of an auto-complete field we have in our system, I came across a very weird bug. The field was supposed to suggest a list of Technicians, based on the name the user typed.

I was asked to have it accept not only the name of the Technician but also their ids.

To make the long story short: we are using a PrimeFaces AutoComplete component with the forceSelection flag set to true. The problem was that even tough the user did not selected any of the suggestions on the list, the value he typed was still being submitted to the form.

At first this was not a problem, because our Converter is using the Technician id, and when searching for a name, there was no match. But when the search includes the id, undesired thing happens, i.e. the field which as supposed to be empty, was filled with the Technician's information whose id the user typed.

With the help of Firebug, I found out that the hidden input Primefaces uses to implement the auto-completion, was not being cleaned when none of the suggestions was picked, thus, submitting a value the user didn't know was there.

To solve the problem, I hacked into Primefaces's jar, and, after formatting the autocomplete.js with the help of my friend Eclipse, I found this line:

jQuery(this).val("");

On a lucky/educated guess, I added the following line below that one:

jQuery(a.jqh).val("");

After repacking the jar, the problem was gone. I am not sure if this is a bug or the correct behavior, but it happened in Primefaces version 2.2.1.

Presentation Layer Validation: Bean Validation Within JSF 2.0

This week, at Elsa Development, we’ve been implementing some customized validators using Bean Validation API. Everything was going fine, until the shadows of Murphy appear. OK, putting aside the drama, a few validators have been implemented successfully, passing all tests, all of them but one...

The Problem

Two constraints were created and for each one, a validator was implemented (which executes the validation logic). Both constraints were used at field-level on JPA entities, the Username and FloatRange constraints were annotated on fields of type string and float, respectively. However, just the Username constraint worked.. Hereunder you can take a look at the implemented code, or part of it :)

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UsernameValidator.class)
@Target({
    ElementType.METHOD,
    ElementType.FIELD,
    ElementType.ANNOTATION_TYPE
})
public @interface Username {
    String message() default "{constraint.username.invalid}";
    Class<? extends Payload>[] payload() default {};
    Class<?>[] groups() default {};
}
Code 1. The working constraint.

public class UsernameValidator
        implements ConstraintValidator<Username, String> {
    @Override
    public void initialize(Username annotation) {}

    @Override
    public boolean isValid(String value,
            ConstraintValidatorContext context) {
        // validation logic ommited
    }
}
Code 2. The validation for @Username constraint.

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = FloatRangeValidator.class)
@Target({
    ElementType.METHOD,
    ElementType.FIELD,
    ElementType.ANNOTATION_TYPE
})
public @interface FloatRange {

    String message() default "{constraint.range}";
    Class<? extends Payload>[] payload() default {};
    Class<?>[] groups() default {};
    float min();
    float max();
}
Code 3. The “murphyfied” constraint (i.e. did not work).

public class FloatRangeValidator
        implements ConstraintValidator<FloatRange, Float> {
    private float min;
    private float max;
 
    @Override
    public void initialize(FloatRange annotation) {
        this.min = annotation.min();
        this.max = annotation.max();
    }

    @Override
    public boolean isValid(Float value,
            ConstraintValidatorContext context) {
        // validation logic ommited
    }
}
Code 4. The “murphyfied” constraint.

The Solution

After a lot of googling and force brute tests... A co worker (Marcelo Yamashita) came with the solution. He tried to use the @FloatRange constraint at property-level, man... that worked! Then, reading more carefully the Hibernate Validator documentation, more specifically the item 2.1.1. Field-level constraints, i noticed the note that says:

Static fields and properties cannot be validated.

 

Well, if i've got it right, by properties it means POJO fields which have getter/setter, or not? If so, then houston, we have a problem... both target annotated fields, belong to JPA entities thus, they have getters and setters! It doesn’t make them properties? Anyway, the workaround rocks, but if you have any idea about the why this happens, please, feel free to share it with the world :)

Test Party

Inspirados em uma Lightening Talk assistida por alguns membros da equipe, realizamos uma Test Party (ou Testing Day, como também é conhecido). Uma Test Party consiste em um momento onde todos os envolvidos no desenvolvimento (desenvolvedores, QA, "gerência", e P.O.s) realizariam testes no sistema, em busca de possíveis erros, de forma que estes não cheguem à produção. O uso de pontuação e gratificação ao final serviriam como estímulo aos participantes.
No nosso caso, participaram as equipes de desenvolvimento e QA. O objetivo era deixar o sistema mais confiável e aumentar a interação das equipes com o sistema do ponto de vista de usuário e não de desenvolvedor.


Os participantes foram organizados em duplas através de sorteio. As regras foram então apresentadas para as duplas:
- O que testar? Deixamos livre a decisão sobre o que cada dupla iria testar, pois o sistema possui diferentes funcionalidades e, portanto,  havia a possibilidade de que a intersecção dos erros encontrados fosse pequena.
- Como testar? Os testes seriam feitos manualmente, de acordo com um objetivo da dupla (realização de uma tarefa no sistema) ou focados na funcionalidade sendo testada. Casos de teste ou erros encontrados poderiam ter scripts de reprodução/automatização criados.
- Pontuação: 1 ponto para bug encontrado, 2 pontos para caso de teste automatizado, e 3 pontos para script que reproduza o bug. A ferramenta utilizada foi o Selenium IDE (pela facilidade e agilidade no uso).
- Gratificação: chocolate para a dupla vencedora.
- Juiz: uma analista de QA foi designada como juiza, confirmando se o comportamento encontrado era de fato um erro e atribuindo os pontos para cada dupla. 

Todos entraram no clima de competição e cada ponto obtido era comemorado pelas duplas. A dinâmica foi bem recebida pela equipe, que se empenhou em fazer bons testes, com mais probabilidade de encontrar erros. 
Algo interessante foi o pouco overlap que ocorreu entre os bugs encontrados, pois cada equipe explorou aspectos diferentes do sistema. Até mesmo em áreas exploradas por mais de uma dupla, diferentes bugs foram encontrados por cada uma. Isso ocorreu não necessariamente pela quantidade de erros naquela região, mas pelo tipo de abordagem de cada dupla.

Em retrospectiva com as equipes, após a "festa", reflexões sobre os pontos positivos e negativos foram feitas. A técnica ajudou os desenvolvedores a sair da zona de conforto e ter contato com problemas que os usuários enfrentam durante o uso. Mesmo com a reformulação do sistema e a aplicação de boas práticas de desenvolvimento, foi possível ver que somente estas não resolvem todos os problemas, e erros podem "escapar" e chegar ao usuário final. A ideia é que o raciocínio utilizado para encontrar os erros seja aplicado na programação, evitando que se repitam.

Sugestões para as próximas edições incluem: 
- Cada dupla ter definidos os seus usuários e os seus participantes específicos para os testes, para não haver conflitos;
- A versão do sistema que será utilizada para os testes deve ser implantada com maior antecedência;
- Definir horário de início e fim, ao invés de aguardar que as duplas terminem suas tarefas;
- Fazer a "festa" fora do horário de expediente para que todos possam se dedicar sem ficar preocupados com as tarefas que "deveriam estar fazendo". Fazendo fora do expediente também permite um clima mais informal, sem pessoas entrando na sala e estranhando as tiaras coloridas e o "clima de festinha" em pleno expediente.

Os erros encontrados foram registrados na nossa ferramenta bug tracker (com seus respectivos scripts de reprodução), geraram tarefas para programação e estão em fase de correção.

A técnica gerou bons resultados e teve feedback positivo. Muitos dos bugs encontrados já foram resolvidos, o uso do Selenium foi incentivado e membros que ainda não o utilizavam com frequência passaram a usar.

Aguardemos então as próximas edições. :)

Tutorial de Instalação do dcm4chee

O dcm4chee é um PACS open source que implementa o padrão DICOM. Ele é compatível com diferentes SGBD’s (MySQL, PostgreSQL, Oracle, etc.) e sistemas operacionais (Windows, Linux e Mac OS).

Neste tutorial vamos descrever a instalação do dcm4chee 2.17.0 em sua versão para o PostgreSQL na plataforma Windows 7 (32 bits). A instalação num ambiente diferente deste pode requerer configurações extras, não descritas neste tutorial.

1. Requisitos básicos

JDK versão 5 ou superior

As instruções de instalação da JDK 6 e a configuração da variável de ambiente JAVA_HOME estão disponíveis aqui.

PostgreSQL

Apesar de já disponível, a versão 9 do PostgreSQL exige configurações extras não abordadas neste tutorial. Recomendamos a versão 8.4, cujas instruções de instalação estão disponíveis aqui.

2. Downloads

JBossAS

O dcm4chee roda sobre o servidor de aplicação JBoss 4.2.3 GA, especificamente. Faça o download do JBoss do site oficial através deste link: jboss-4.2.3.GA.zip.

dcm4chee

Faça o download do dcm4chee em sua versão para o PostgreSQL do site oficial através deste link: dcm4chee-2.17.0-psql.zip.

ARR

O dcm4chee permite a auditoria das operações realizadas, como transferência de arquivos, buscas, etc. Porém esta funcionalidade está num módulo separado, o Audit Record Repository (ARR). Faça o download do ARR em sua versão para o PostgreSQL do site oficial através deste link: dcm4chee-arr-3.0.11-psql.zip.

3. Estrutura de pastas

Descompacte os arquivos baixados na seção anterior numa pasta de sua preferência. É importante o caminho da pasta não conter espaços, pois isto pode acarretar em erros na instalação.

No exemplo deste tutorial vamos extraí-los na pasta “C:\dicom”. Assim, teremos a estrutura de pastas da figura abaixo:



4. Bases de dados

pacsdb

Para criar a base de dados utilizada pelo dcm4chee, abra o prompt de comando e execute o comando “createdb” passando o nome da nova base de dados, “pacsdb”. No exemplo deste tutorial o comando fica assim: “createdb -U postgres pacsdb”.



O parâmetro “postgres” é o usuário utilizado para conectar no banco de dados, no caso o super-usuário, por questões de permissão. O mesmo será passado como parâmetro nos comandos seguintes.

O script de criação das tabelas e outras estruturas da base de dados “pacsdb” está disponível no arquivo “create.psql”, presente na pasta “sql”, dentro da pasta raiz de instalação do dcm4chee.

Execute o comando “psql” passando como parâmetros o nome da base de dados, “pacsdb”, e o arquivo que contém o script. No exemplo deste tutorial o comando fica assim: “psql -d pacsdb -U postgres -f C:\dicom\dcm4chee-2.17.0-psql\sql\create.psql”.



arrdb

O ARR possui sua própria base de dados, de nome “arrdb”. Para criar esta base de dados, no prompt de comando execute o comando “createdb” passando o nome da nova base de dados, “arrdb”. No exemplo deste tutorial o comando fica assim: “createdb -U postgres arrdb”.



O script de criação das tabelas e outras estruturas da base de dados “arrdb” está disponível no arquivo “dcm4chee-arr-sql.ddl”, presente na pasta “sql”, dentro da pasta raiz de instalação do ARR.

Execute o comando “psql” passando como parâmetros o nome da base de dados, “arrdb”, e o arquivo que contém o script. No exemplo deste tutorial o comando fica assim: “psql -d arrdb -U postgres -f C:\dicom\dcm4chee-arr-3.0.11-psql\sql\dcm4chee-arr-sql.ddl”.



Permissões

Para que o dcm4chee e o ARR consigam acessar as suas bases de dados é preciso configurar as respectivas conexões no arquivo “pg_hba.conf”, localizado na pasta “data” dentro da pasta raiz de instalação do PostgreSQL.
No exemplo deste tutorial é a pasta: “C:\Program Files\PostgreSQL\8.4\data”.

Neste arquivo adicione as linhas:
host    pacsdb      postgres    127.0.0.1/32          trust
host arrdb postgres 127.0.0.1/32 trust
Logo acima da linha:
host    all         all         127.0.0.1/32          md5
Conforme a figura abaixo.



Salve o arquivo. Esta configurção dá permissão de acesso às bases de dados pacsdb e arrdb para o usuário “postgres” (utilizado pelo dcm4chee e pelo ARR por padrão) para conexões solicitadas pelo IP local (127.0.0.1). Para outras conexões é solicitada a senha do usuário.

5. Scripts finais de instalação

O próximo passo da instalação do dcm4chee é rodar o script “install_jboss.bat”, localizado na pasta “bin” dentro da pasta raiz de instalação do dcm4chee, passando a pasta raiz de instalação do JBoss como parâmetro. No exemplo deste tutorial o comando para executar este script fica assim:
“install_jboss C:\dicom\jboss-4.2.3.GA”.



Este script vai integrar o dcm4chee com o JBoss, copiando arquivos deste último para a estrutura de pastas do dcm4chee.

Para completar a instalação, temos de rodar o script “install_arr.bat”, localizado na pasta “bin” dentro da pasta raiz de instalação do dcm4chee, passando a pasta raiz de instalação do ARR. No exemplo deste tutorial o comando para executar o script fica assim: “install_arr C:\dicom\dcm4chee-arr-3.0.11-psql”.



Este script vai integrar o dcm4chee com o ARR, copiando arquivos deste último para a estrutura de pastas do dcm4chee.

Pronto. A instalação está completa.

6. Testando a instalação

Para testar a instalação, execute o script “run.bat”, localizado na pasta “bin” dentro da pasta raiz de instalação do dcm4chee. Este script vai inicializar o servidor dcm4chee.



Se todos os passos anteriores deram certo, não haverá mensagem de erro (ERROR) na console, apenas informativas (INFO), como na figura abaixo.



Para testar o dcm4chee, acesse a URL “http://localhost:8080/dcm4chee-web” no seu navegador. Faça o login com o usuário “admin” e senha “admin”.

Para testar o ARR, clique no link “Audit Repository”. Forneça o usuário “admin” e a senha “admin”.

Para parar o dcm4chee pressione as teclas Ctrl + C na console onde o dcm4chee foi inicializado.

7. Configurações adicionais

Permissões do sistema de arquivos

Para configurar as permissões de escrita e leitura do dcm4chee no sistema de arquivos do Windows, acesse a URL “http://localhost:8080/jmx-console” no seu browser (o dcm4chee tem de estar inicializado). Forneça o usuário “admin” e a senha “admin”.

Selecione o link “group=ONLINE_STORAGE, service=FileSystemMgt”, sob o cabeçalho “dcm4chee.archive”.



Localize o cabeçalho “addRWFileSystem()”



Clique no botão “Invoke”.

Instalar o dcm4chee como serviço

Para não ter de executar o comando “run” a cada vez que for utilizar o dcm4chee, você pode instalá-lo como um serviço do Windows. Assim, ele será inicializado a cada vez que o Windows iniciar.

Para tanto, execute o script “install_service.bat”, localizado na pasta “bin” dentro da pasta raiz de instalação do dcm4chee, passando o parâmetro “service”.



Se receber uma mensagem de acesso negado, abra o prompt de comando como administrador (clique com o botão direito do mouse sobre o ícone do prompt de comando e selecione a opção “Executar como administrador”) e tente novamente.

Instalação do PostgreSQL

Neste tutorial vamos instalar o PostgreSQL 8.4 no Windows 7 Professional.

Faça o download da versão 8.4.8-1 para Windows do PostgreSQL:

http://www.enterprisedb.com/products-services-training/pgdownload

Execute o instalador baixado (arquivo postgresql-8.4.1-1-windows.exe).

Aparecerá a tela de boas vindas.



Clique no botão “Next”.


Será solicitada a escolha de um diretório raiz para a instalação do PostgreSQL. Por padrão a instalação ocorre no diretório “C:\Program Files\PostgreSQL\8.4”.



Clique no botão “Next”.


Será solicitada a escolha de um diretório de armazenamento dos dados do banco. Por padrão a instalação ocorre no diretório “C:\Program Files\PostgreSQL\8.4\data”.



Clique no botão “Next”.


Será solicitada a escolha da senha do super-usuário do banco de dados. Digite a senha escolhida e repita-a no segundo campo para a confirmação.



Clique no botão “Next”.


Será solicitada a escolha do número da porta, a ser utilizado por outras aplicações para conectarem-se ao banco de dados. Recomenda-se deixar o padrão 5432.



Clique no botão “Next”.


Na próxima tela será solicitada a escolha da localidade, para as configurações de linguagem da interface e formatos de data. Selecione “Portuguese, Brazil”. Nesta mesma tela você também pode escolher se deseja que a linguagem pl/psql seja instalada.



Clique no botão “Next”.


A próxima tela apenas informa que o instalador está pronto para iniciar a instalação.



Clique no botão “Next”.


Aguarde a instalação terminar.



Clique no botão “Next”.


Pronto, a instação está conculída. Caso queira instalar complementos ao PostgreSQL deixe marcada a opção “Launch Stack Builder at exit?”. Senão, desmarque esta opção.



Clique no botão “Finish”.


A partir de agora você pode gerenciar seu banco de dados através da aplicação pgAdmin, que oferece uma interface gráfica pra tanto.



Você também pode gerenciá-lo através do prompt de comando, chamando o comando “psql” na pasta “bin” dentro do diretório de instalação do PostgreSQL (para o diretório padrão da instalação, é a pasta “C:\Program Files\PostgreSQL\8.4\bin”).


No exemplo abaixo, estou chamando o comando psql passando o nome do usuário “postgres” como parâmetro. Para maiores detalhes sobre os parâmetros, chame o comando “psql --help”.



Para mostrar a lista de comandos do psql digite “\?”. Para mostrar a lista de comandos SQL digite “\h”. Para sair do psql digite o comando “\q”.
Para executar o psql de qualquer diretório, adicione o caminho da pasta “bin” do PostgreSQL à variável de ambiente “Path” do Windows.

A mensagem de aviso da imagem acima ocorre porque a página de código padrão do prompt de comando do Windows difere da utilizada pelo psql. Para evitar este problema, temos de alterar a página de código do prompt de comando do windows. Para isso, antes de chamar o psql, digite o comando "cmd /c chcp 1252".



Isto vai recarregar o prompt de comando com a página de código utilizada pelo psql. Porém, a fonte padrão do prompt de comando não é adequada para esta página de código, tendo de ser alterada. Para tanto, clique com o botão direito do mouse sobre a barra superior da janela e selecione a opção "Propriedades".



Na aba "Fonte", selecione a fonte "Lucida Console" e clique no botão "OK".



Pronto, agora você pode chamar o comando psql sem problemas.


All Tests?

Uma das características mais presentes no nosso dia-a-dia de desenvolvimento é a interiorização de práticas de integração contínua. Todos temos o hábito de baixar para a própria máquina todos os códigos-fonte, no início do dia. Trabalhar sobre eles até que, ao final do dia, seja feito upload/commit das modificações. Sem erros, claro.

No entanto, acabamos descobrindo esses dias que algumas vezes a prática de subir para o servidor os novos códigos estava quebrando a regra de termos apenas códigos 100%. Nos cobramos mutuamente na retrospectiva, mas não tínhamos a detecção real do problema.

Eis que alguém resolveu dar uma olhada no AllTests e descobriu o real problema: nem todas as novas classes de teste estavam sendo adicinoadas lá. Com isso, alguns testes não estavam sendo executados, e erros não estavam sendo encontrados. Se uma solução rápida seria atualizar a suíte de teste, decidimos por uma ainda mais ágil: apagar a suíte.

Por mais que a decisão pareça radical, ela é simples: ao invés de mandar rodar o AllTests, usamos o botão direito em cima da fonte de código com os pacotes de teste e um "Run As..". Esse procedimento executa absolutamente todos os testes, no Eclipse. Agora, voltamos a ter certeza que o servidor está 100%.